一、Collector常常出現的地方
java8引入了stream,Collector是與stream一起出現的,配合stream使用的好幫手,如果用過stream,我們應該都有寫過這樣的代碼
例子1:
1
|
lists.stream()....collect(Collectors.toList()); |
例子2:
1
|
lists.stream().collect(groupingBy(String::length)); |
這兩個例子中,toList()和groupingBy()返回的都是一個Collector對象,那么問題來了,什么是Collector?
二、什么是Collector
Collector其實是一個泛型接口,通過這個接口可以定義一系列的聚合操作,按照官方文檔的說法,Collector其實是提供mutable reduction operation,即可改變的減少操作。
常見的聚合操作有:
1.用StringBuilder拼接字符串
2.計算元素綜合的數據,比如sum, min, max, or average
這個reduction在Google翻譯是減少的意思,但是我不太對得上這個意思,覺得形容成聚合操作會更容易理解一點。
關于聚合操作,我們會在很多語言中遇到,比如mysql里面的group by操作,sum(),min(),max(),Count(),anyValue(),這些叫做aggregate function,即聚合操作
我理解這些操作的是類似的,只不過這些是在數據庫里面進行的,collector是在java代碼層進行的,他們的本質都是一樣的,他們都進行了多對一的轉換,將一系列的數據變成一個數據或者幾團數據。
三、Collector的使用
Collector是一個接口,它還有一個靜態工具類Collectors,Collectors提供了很多常見的聚合操作的實現,通常來說我們調用Collectors里面的方法就夠了,如果想要更多更復雜的實現也可以自定義一個collector,定義Collector的話,我們需要先了解Collector的組成
3.1 Collector的泛型類型
collector是一個泛型接口,那我們先從泛型的元素開始分析
Collector<T, A, R>
這個接口有三種類型,T代表流中元素的類型,A是中間結果容器的類型,R是最后返回的類型
比如一個字符串數組strings,對它進行這個操作
1
|
strings.stream()....collect(Collectors.toList()); |
toList()方法返回的Collector中,T就是String類型,A是List<String>類型,R是List<String>類型,如果不能理解可以繼續往下看
3.2 Collector 的組成
collector由四個方法組成和一個特性組成
組成 | 作用 |
---|---|
Supplier | 創建一個新的結果容器 |
accumulator | 將一個新的元素(流中的元素)加入到結果容器中 |
combiner | 接受兩個中間的結果容器,將它們合并成一個(并行流的時候) |
finisher | 將結果容器轉換成另一個類型(可選的) |
characteristics 是一個枚舉特性集合,決定某些操作過程的特性,比如是否是并行的,是否需要轉換結果容器,是否是有序的,這些特性用來進行簡化操作,提供更好的性能。
一共有三個特性,在定義的時候可以選幾個來組成這個集合,它們是:
- CONCURRENT :意味著這個同一個容器可以被多個線程調用accumulator方法進行操作
- UNORDERED:意味著這個聚合操作不會保留元素的出現順序,一般是來說最后的結果容器是無序的(比如Set)才會使用
- IDENTITY_FINISH:意味著finisher方法是Function.identity(),可以被省略,如果設置了的話,需要A類型可以能強制地轉換成R類型,否則會拋出異常。
關于Collector的四個方法,這里用一個流程圖來解釋這個過程
3.3 舉例解釋Collector四個方法
下面通過Collectors里面提供的常見方法來詳細地說明Collector的組成
3.3.1 Example1- toList()
首先來看toList()方法的組成
1
2
3
4
5
|
public static <T> Collector<T, ?, List<T>> toList() { return new CollectorImpl<>((Supplier<List<T>>) ArrayList:: new , List::add, (left, right) -> { left.addAll(right); return left; }, CH_ID); } |
對于這個方法實現來說
- supplier是 () -> ArrayList::new,提供的容器類型(A)是ArrayList
- accumulator是List::add,將元素item加入到arrayList容器中,即
(intermediateCollector, item) -> intermediateCollector.add(item)
- combiner是將兩個容器arrayList合并
(left, right) -> { left.addAll(right); return left;}
- finisher是啥也不做,combiner之后的結果就直接返回來,所以R也是ArrayList的類型
- characteristic是
Collections.unmodifiableSet(EnumSet.of(Collector.Characteristics.IDENTITY_FINISH));
IDENTITY_FINISH這個特性是說,不執行finisher函數,直接返回combiner之后的結果容器
3.3.2 Example2- joining()
joining有三個方法重載,我們這里先看最直觀的一個,它的實現是
1
2
3
4
5
6
|
public static Collector<CharSequence, ?, String> joining() { return new CollectorImpl<CharSequence, StringBuilder, String>( StringBuilder:: new , StringBuilder::append, (r1, r2) -> { r1.append(r2); return r1; }, StringBuilder::toString, CH_NOID); } |
- supplier是StringBuilder::new,即:
() -> new StringBuilder();
容器A的類型是StringBuilder
- accumulator是StringBuilder::append, 即
(intermediate, current)-> intermediare.append(current);
- combiner是
(r1, r2) -> { r1.append(r2); return r1; }
即對于兩個中間的結果stringBuilder來說,combiner做的事情就是合并兩個stringBuilder,變成一個stringBuilder
- finisher是StringBuilder::toString,對于最后的容器StringBuilder,finisher會將它轉換成String的類型,因此R的類型是String
- characteristic是一個emptySet(),不包含任何特性
Collections.emptySet();
到此這篇關于詳解Java中Collector接口的組成的文章就介紹到這了,更多相關Collector接口的組成內容請搜索服務器之家以前的文章或繼續瀏覽下面的相關文章希望大家以后多多支持服務器之家!
原文鏈接:https://blog.csdn.net/lingfy1234/article/details/117887349