原創做品,能夠轉載,可是請標註出處地址:http://www.javashuo.com/article/p-glxabwle-do.htmlhtml
Collector是專門用來做爲Stream的collect方法的參數的。java
public interface Stream<T> extends BaseStream<T, Stream<T>> { <R, A> R collect(Collector<? super T, A, R> collector); }
而Collectors是做爲生產具體Collector的工具類。api
Collector主要包含五個參數,它的行爲也是由這五個參數來定義的,以下所示:多線程
public interface Collector<T, A, R> { // supplier參數用於生成結果容器,容器類型爲A Supplier<A> supplier(); // accumulator用於消費元素,也就是概括元素,這裏的T就是元素,它會將流中的元素一個一個與結果容器A發生操做 BiConsumer<A, T> accumulator(); // combiner用於兩個兩個合併並行執行的線程的執行結果,將其合併爲一個最終結果A BinaryOperator<A> combiner(); // finisher用於將以前整合完的結果R轉換成爲A Function<A, R> finisher(); // characteristics表示當前Collector的特徵值,這是個不可變Set Set<Characteristics> characteristics(); }
Collector擁有兩個of方法用於生成Collector實例,其中一個擁有上面全部五個參數,另外一個四個參數,不包括finisher。併發
public interface Collector<T, A, R> { // 四參方法,用於生成一個Collector,T表明流中的一個一個元素,R表明最終的結果 public static<T, R> Collector<T, R, R> of(Supplier<R> supplier, BiConsumer<R, T> accumulator, BinaryOperator<R> combiner, Characteristics... characteristics) {/*...*/} // 五參方法,用於生成一個Collector,T表明流中的一個一個元素,A表明中間結果,R表明最終結果,finisher用於將A轉換爲R public static<T, A, R> Collector<T, A, R> of(Supplier<A> supplier, BiConsumer<A, T> accumulator, BinaryOperator<A> combiner, Function<A, R> finisher, Characteristics... characteristics) {/*...*/} }
Characteristics:這個特徵值是一個枚舉,擁有三個值:CONCURRENT(多線程並行),UNORDERED(無序),IDENTITY_FINISH(無需轉換結果)。其中四參of方法中沒有finisher參數,全部必有IDENTITY_FINISH特徵值。app
Collectors是一個工具類,是JDK預實現Collector的工具類,它內部提供了多種Collector,咱們能夠直接拿來使用,很是方便。ide
將流中的元素所有放置到一個集合中返回,這裏使用Collection,泛指多種集合。工具
public class CollectorsTest { public static void toCollectionTest(List<String> list) { List<String> ll = list.stream().collect(Collectors.toCollection(LinkedList::new)); } public static void main(String[] args) { List<String> list = Arrays.asList("123","456","789","1101","212121121","asdaa","3e3e3e","2321eew"); toCollectionTest(list); } }
將流中的元素放置到一個列表集合中去。這個列表默認爲ArrayList。線程
public class CollectorsTest { public static void toListTest(List<String> list) { List<String> ll = list.stream().collect(Collectors.toList()); } public static void main(String[] args) { List<String> list = Arrays.asList("123","456","789","1101","212121121","asdaa","3e3e3e","2321eew"); toListTest(list); } }
將流中的元素放置到一個無序集set中去。默認爲HashSet。code
public class CollectorsTest { public static void toSetTest(List<String> list) { Set<String> ss = list.stream().collect(Collectors.toSet()); } public static void main(String[] args) { List<String> list = Arrays.asList("123","456","789","1101","212121121","asdaa","3e3e3e","2321eew"); toSetTest(list); } }
joining的目的是將流中的元素所有以字符序列的方式鏈接到一塊兒,能夠指定鏈接符,甚至是結果的先後綴。
public class CollectorsTest { public static void joiningTest(List<String> list){ // 無參方法 String s = list.stream().collect(Collectors.joining()); System.out.println(s); // 指定鏈接符 String ss = list.stream().collect(Collectors.joining("-")); System.out.println(ss); // 指定鏈接符和先後綴 String sss = list.stream().collect(Collectors.joining("-","S","E")); System.out.println(sss); } public static void main(String[] args) { List<String> list = Arrays.asList("123","456","789","1101","212121121","asdaa","3e3e3e","2321eew"); joiningTest(list); } }
執行結果:
1234567891101212121121asdaa3e3e3e2321eew 123-456-789-1101-212121121-asdaa-3e3e3e-2321eew S123-456-789-1101-212121121-asdaa-3e3e3e-2321eewE
StringJoiner:這是一個字符串鏈接器,能夠定義鏈接符和先後綴,正好適用於實現第三種joining方法。
這個映射是首先對流中的每一個元素進行映射,即類型轉換,而後再將新元素以給定的Collector進行概括。
public class CollectorsTest { public static void mapingTest(List<String> list){ List<Integer> ll = list.stream().limit(5).collect(Collectors.mapping(Integer::valueOf,Collectors.toList())); } public static void main(String[] args) { List<String> list = Arrays.asList("123","456","789","1101","212121121","asdaa","3e3e3e","2321eew"); mapingTest(list); } }
實例中截取字符串列表的前5個元素,將其分別轉換爲Integer類型,而後放到一個List中返回。
該方法是在概括動做結束以後,對概括的結果進行再處理。
public class CollectorsTest { public static void collectingAndThenTest(List<String> list){ int length = list.stream().collect(Collectors.collectingAndThen(Collectors.toList(),e -> e.size())); System.out.println(length); } public static void main(String[] args) { List<String> list = Arrays.asList("123","456","789","1101","212121121","asdaa","3e3e3e","2321eew"); collectingAndThenTest(list); } }
執行結果爲:
8
該方法用於計數。
public class CollectorsTest { public static void countingTest(List<String> list){ long size = list.stream().collect(Collectors.counting()); System.out.println(size); } public static void main(String[] args) { List<String> list = Arrays.asList("123","456","789","1101","212121121","asdaa","3e3e3e","2321eew"); countingTest(list); } }
結果:
8
生成一個用於獲取最小/最大值的Optional結果的Collector。
public class CollectorsTest { public static void maxByAndMinByTest(List<String> list){ System.out.println(list.stream().collect(Collectors.maxBy((a,b) -> a.length()-b.length()))); System.out.println(list.stream().collect(Collectors.minBy((a,b) -> a.length()-b.length()))); } public static void main(String[] args) { List<String> list = Arrays.asList("123","456","789","1101","212121121","asdaa","3e3e3e","2321eew"); maxByAndMinByTest(list); } }
執行結果爲:
Optional[212121121] Optional[123]
生成一個用於求元素和的Collector,首先經過給定的mapper將元素轉換類型,而後再求和。
參數的做用就是將元素轉換爲指定的類型,最後結果與轉換後類型一致。
public class CollectorsTest { public static void summingTest(List<String> list){ int i = list.stream().limit(3).collect(Collectors.summingInt(Integer::valueOf)); long l = list.stream().limit(3).collect(Collectors.summingLong(Long::valueOf)); double d = list.stream().limit(3).collect(Collectors.summingDouble(Double::valueOf)); System.out.println(i +"\n" +l + "\n" + d); } public static void main(String[] args) { List<String> list = Arrays.asList("123","456","789","1101","212121121","asdaa","3e3e3e","2321eew"); summingTest(list); } }
執行結果爲:
1368 1368 1368.0
生成一個用於求元素平均值的Collector,首選經過參數將元素轉換爲指定的類型。
參數的做用就是將元素轉換爲指定的類型,求平均值涉及到除法操做,結果一概爲Double類型。
public class CollectorsTest { public static void averagingTest(List<String> list){ double i = list.stream().limit(3).collect(Collectors.averagingInt(Integer::valueOf)); double l = list.stream().limit(3).collect(Collectors.averagingLong(Long::valueOf)); double d = list.stream().limit(3).collect(Collectors.averagingDouble(Double::valueOf)); System.out.println(i +"\n" +l + "\n" + d); } public static void main(String[] args) { List<String> list = Arrays.asList("123","456","789","1101","212121121","asdaa","3e3e3e","2321eew"); averagingTest(list); } }
執行結果爲:
456.0 456.0 456.0
reducing方法有三個重載方法,實際上是和Stream裏的三個reduce方法對應的,兩者是能夠替換使用的,做用徹底一致,也是對流中的元素作統計概括做用。
public final class Collectors { // 無初始值的狀況,返回一個能夠生成Optional結果的Collector public static <T> Collector<T, ?, Optional<T>> reducing(BinaryOperator<T> op) {/*...*/} // 有初始值的狀況,返回一個能夠直接產生結果的Collector public static <T> Collector<T, ?, T> reducing(T identity, BinaryOperator<T> op) {/*...*/} // 有初始值,還有針對元素的處理方案mapper,生成一個能夠直接產生結果的Collector,元素在執行結果操做op以前須要先執行mapper進行元素轉換操做 public static <T, U> Collector<T, ?, U> reducing(U identity, Function<? super T, ? extends U> mapper, BinaryOperator<U> op) {/*...*/} }
實例:
public class CollectorsTest { public static void reducingTest(List<String> list){ System.out.println(list.stream().limit(4).map(String::length).collect(Collectors.reducing(Integer::sum))); System.out.println(list.stream().limit(3).map(String::length).collect(Collectors.reducing(0, Integer::sum))); System.out.println(list.stream().limit(4).collect(Collectors.reducing(0,String::length,Integer::sum))); } public static void main(String[] args) { List<String> list = Arrays.asList("123","456","789","1101","212121121","asdaa","3e3e3e","2321eew"); reducingTest(list); } }
Optional[13] 9 13
效果可參見Java基礎系列-Stream
這個方法是用於生成一個擁有分組功能的Collector,它也有三個重載方法:
public final class Collectors { // 只需一個分組參數classifier,內部自動將結果保存到一個map中,每一個map的鍵爲?類型(即classifier的結果類型),值爲一個list,這個list中保存在屬於這個組的元素。 public static <T, K> Collector<T, ?, Map<K, List<T>>> groupingBy( Function<? super T, ? extends K> classifier) {/*...*/} // 在上面方法的基礎上增長了對流中元素的處理方式的Collector,好比上面的默認的處理方法就是Collectors.toList() public static <T, K, A, D>Collector<T, ?, Map<K, D>> groupingBy( Function<? super T, ? extends K> classifier,Collector<? super T, A, D> downstream) {/*...*/} // 在第二個方法的基礎上再添加告終果Map的生成方法。 public static <T, K, D, A, M extends Map<K, D>> Collector<T, ?, M> groupingBy(Function<? super T, ? extends K> classifier, Supplier<M> mapFactory, Collector<? super T, A, D> downstream) {/*...*/} }
實例:
public class CollectorsTest { public static void groupingByTest(List<String> list){ Map<Integer,List<String>> s = list.stream().collect(Collectors.groupingBy(String::length)); Map<Integer,List<String>> ss = list.stream().collect(Collectors.groupingBy(String::length, Collectors.toList())); Map<Integer,Set<String>> sss = list.stream().collect(Collectors.groupingBy(String::length,HashMap::new,Collectors.toSet())); System.out.println(s.toString() + "\n" + ss.toString() + "\n" + sss.toString()); } public static void main(String[] args) { List<String> list = Arrays.asList("123","456","789","1101","212121121","asdaa","3e3e3e","2321eew"); groupingByTest(list); } }
執行結果爲:
{3=[123, 456, 789], 4=[1101], 5=[asdaa], 6=[3e3e3e], 7=[2321eew], 9=[212121121]} {3=[123, 456, 789], 4=[1101], 5=[asdaa], 6=[3e3e3e], 7=[2321eew], 9=[212121121]} {3=[123, 456, 789], 4=[1101], 5=[asdaa], 6=[3e3e3e], 7=[2321eew], 9=[212121121]}
groupingBy方法還有併發版的groupingByConcurrent,功能基本一致,只是返回的Collector是並行的。
該方法將流中的元素按照給定的校驗規則的結果分爲兩個部分,放到一個map中返回,map的鍵是Boolean類型,值爲元素的列表List。
該方法有兩個重載方法:
public final class Collectors { // 只需一個校驗參數predicate public static <T> Collector<T, ?, Map<Boolean, List<T>>> partitioningBy(Predicate<? super T> predicate) {/*...*/} // 在上面方法的基礎上增長了對流中元素的處理方式的Collector,好比上面的默認的處理方法就是Collectors.toList() public static <T, D, A> Collector<T, ?, Map<Boolean, D>> partitioningBy(Predicate<? super T> predicate, Collector<? super T, A, D> downstream) {/*...*/} }
實例:
public class CollectorsTest { public static void partitioningByTest(List<String> list){ Map<Boolean,List<String>> map = list.stream().collect(Collectors.partitioningBy(e -> e.length()>5)); Map<Boolean,Set<String>> map2 = list.stream().collect(Collectors.partitioningBy(e -> e.length()>6,Collectors.toSet())); System.out.println(map.toString() + "\n" + map2.toString()); } public static void main(String[] args) { List<String> list = Arrays.asList("123","456","789","1101","212121121","asdaa","3e3e3e","2321eew"); partitioningByTest(list); } }
執行結果:
{false=[123, 456, 789, 1101, asdaa], true=[212121121, 3e3e3e, 2321eew]} {false=[123, 456, 1101, 789, 3e3e3e, asdaa], true=[212121121, 2321eew]}
toMap方法是根據給定的鍵生成器和值生成器生成的鍵和值保存到一個map中返回,鍵和值的生成都依賴於元素,能夠指定出現重複鍵時的處理方案和保存結果的map。
public final class Collectors { // 指定鍵和值的生成方式keyMapper和valueMapper public static <T, K, U> Collector<T, ?, Map<K,U>> toMap(Function<? super T, ? extends K> keyMapper, Function<? super T, ? extends U> valueMapper) {/*...*/} // 在上面方法的基礎上增長了對鍵發生重複時處理方式的mergeFunction,好比上面的默認的處理方法就是拋出異常 public static <T, K, U> Collector<T, ?, Map<K,U>> toMap(Function<? super T, ? extends K> keyMapper, Function<? super T, ? extends U> valueMapper, BinaryOperator<U> mergeFunction) {/*...*/} // 在第二個方法的基礎上再添加告終果Map的生成方法。 public static <T, K, U, M extends Map<K, U>> Collector<T, ?, M> toMap(Function<? super T, ? extends K> keyMapper, Function<? super T, ? extends U> valueMapper, BinaryOperator<U> mergeFunction, Supplier<M> mapSupplier) {/*...*/} }
實例:
public class CollectorsTest { public static void toMapTest(List<String> list){ Map<String,String> map = list.stream().limit(3).collect(Collectors.toMap(e -> e.substring(0,1),e -> e)); Map<String,String> map1 = list.stream().collect(Collectors.toMap(e -> e.substring(0,1),e->e,(a,b)-> b)); Map<String,String> map2 = list.stream().collect(Collectors.toMap(e -> e.substring(0,1),e->e,(a,b)-> b,HashMap::new)); System.out.println(map.toString() + "\n" + map1.toString() + "\n" + map2.toString()); } public static void main(String[] args) { List<String> list = Arrays.asList("123","456","789","1101","212121121","asdaa","3e3e3e","2321eew"); toMapTest(list); } }
執行結果:
{1=123, 4=456, 7=789} {a=asdaa, 1=1101, 2=2321eew, 3=3e3e3e, 4=456, 7=789} {a=asdaa, 1=1101, 2=2321eew, 3=3e3e3e, 4=456, 7=789}
第一種方式中,若是不添加limit限制,就會拋出異常。
還有併發的版本:toConcurrentMap,一樣三種重載方法,與toMap基本一致,只是它最後使用的map是併發Map:ConcurrentHashMap。
這三個方法適用於彙總的,返回值分別是IntSummaryStatistics,LongSummaryStatistics,DoubleSummaryStatistics。
在這些返回值中包含有流中元素的指定結果的數量、和、最大值、最小值、平均值。全部僅僅針對數值結果。
public class CollectorsTest { public static void summarizingTest(List<String> list){ IntSummaryStatistics intSummary = list.stream().collect(Collectors.summarizingInt(String::length)); LongSummaryStatistics longSummary = list.stream().limit(4).collect(Collectors.summarizingLong(Long::valueOf)); DoubleSummaryStatistics doubleSummary = list.stream().limit(3).collect(Collectors.summarizingDouble(Double::valueOf)); System.out.println(intSummary.toString() + "\n" + longSummary.toString() + "\n" + doubleSummary.toString()); } public static void main(String[] args) { List<String> list = Arrays.asList("123","456","789","1101","212121121","asdaa","3e3e3e","2321eew"); summarizingTest(list); } }
執行結果:
IntSummaryStatistics{count=8, sum=40, min=3, average=5.000000, max=9} LongSummaryStatistics{count=4, sum=2469, min=123, average=617.250000, max=1101} DoubleSummaryStatistics{count=3, sum=1368.000000, min=123.000000, average=456.000000, max=789.000000}
最後咱們能夠從返回的彙總實例中獲取到想要的彙總結果。
整個Collectors工具類就是在爲Collector服務,用於建立各類不一樣的Collector。部分功能與Stream中的方法重合了,爲了簡化代碼,徹底沒必要採用Collectors實現,優先Stream方法。
參考: