[四] java8 函數式編程 收集器淺析 收集器Collector經常使用方法 運行原理 內部實現

Collector常見用法

 
 
經常使用形式爲:   .collect(Collectors.toList())
collect()是Stream的方法
Collectors  是收集器Collector 的工廠方法,提供了一些經常使用的收集器 
好比
image_5b7bb60d_263d
image_5b7bb60d_7cfe


經常使用收集器概要

收集器 行爲
toList() 將元素收集到一個  List 中。
toSet() 將元素收集到一個  Set 中。
toCollection() 將元素收集到一個  Collection 中。
toMap(...) 將元素收集到一個  Map 中,依據提供的映射函數將元素轉換爲鍵/值。
summingInt(ToIntFunction<? super T>) 給定值序列進行求和(還有  long 和  double 版本)
summarizingInt(ToIntFunction<T>) 給定值序列計算統計信息 sum min max count 和  average   (還有  long 和  double 版本)
reducing(...) 用於歸約計算(一般用做下游收集器,好比用於  groupingBy 或者partitioningBy 下游
partitioningBy(...) 按照predicate分爲兩組
groupingBy(...) 將元素分組
maxBy(Comparator<? super T> comparator) 最大值
minBy(Comparator<? super T> comparator) 最小值
mapping(Function<T,U>, Collector) 將提供的映射函數應用於每一個元素,並使用指定的下游收集器(一般用做下游收集器自己,好比用於  groupingBy)進行處理。
joining() 假設元素爲  String 類型,將這些元素聯結到一個字符串中(或許使用分隔符、前綴和後綴)。
counting() 計算元素數量。(一般用做下游收集器。)
averagingInt(ToIntFunction<? super T>) 平均數     (還有  long 和  double 版本)
 

收集器參數列表

toList()
toSet()
toCollection(Supplier<C>)
counting()
collectingAndThen(Collector<T, A, R>, Function<R, RR>)
summingInt(ToIntFunction<? super T>)
summingLong(ToLongFunction<? super T>)
summingDouble(ToDoubleFunction<? super T>)
maxBy(Comparator<? super T>)
minBy(Comparator<? super T>)
reducing(BinaryOperator<T>)
reducing(T, BinaryOperator<T>)
reducing(U, Function<? super T, ? extends U>, BinaryOperator<U>)
joining()
joining(CharSequence)
joining(CharSequence, CharSequence, CharSequence)
mapping(Function<? super T, ? extends U>, Collector<? super U, A, R>)
toMap(Function<? super T, ? extends K>, Function<? super T, ? extends U>)
toMap(Function<? super T, ? extends K>, Function<? super T, ? extends U>, BinaryOperator<U>)
toMap(Function<? super T, ? extends K>, Function<? super T, ? extends U>, BinaryOperator<U>, Supplier<M>)
toConcurrentMap(Function<? super T, ? extends K>, Function<? super T, ? extends U>)
toConcurrentMap(Function<? super T, ? extends K>, Function<? super T, ? extends U>, BinaryOperator<U>)
toConcurrentMap(Function<? super T, ? extends K>, Function<? super T, ? extends U>, BinaryOperator<U>, Supplier<M>)
groupingBy(Function<? super T, ? extends K>)
groupingBy(Function<? super T, ? extends K>, Supplier<M>, Collector<? super T, A, D>)
groupingBy(Function<? super T, ? extends K>, Collector<? super T, A, D>)
groupingByConcurrent(Function<? super T, ? extends K>)
groupingByConcurrent(Function<? super T, ? extends K>, Supplier<M>, Collector<? super T, A, D>)
groupingByConcurrent(Function<? super T, ? extends K>, Collector<? super T, A, D>)
partitioningBy(Predicate<? super T>)
partitioningBy(Predicate<? super T>, Collector<? super T, A, D>)
averagingDouble(ToDoubleFunction<? super T>)
averagingInt(ToIntFunction<? super T>)
averagingLong(ToLongFunction<? super T>)
summarizingDouble(ToDoubleFunction<? super T>)
summarizingInt(ToIntFunction<? super T>)
summarizingLong(ToLongFunction<? super T>)
 


收集器詳解


Collector
image_5b7bb60d_7a4f
T - 輸入類型
A - 在收集過程當中用於累積部分結果的對象類型
R - 返回類型
 
 
mutable reduction的一些場景:
將元素彙集到集合中
使用StringBuilder鏈接字符串
計算有關元素的彙總信息,如sum、min、max或平均值
計算「主表」摘要,如「賣方的最大價值交易」等
類Collectors提供了許多常見的reduce實現
 

收集器構成

收集器是由四個函數約定構成,它們一塊兒工做,將條目聚集到一個可變的結果容器中,並可選擇性地對結果執行最終轉換。
 
1. 建立一個新的結果容器(supplier())
2.  將一個新的數據元素合併到一個結果容器中(accumulator())
3. 將兩個結果容器合併成一個(combiner())             
     (非必然運行  可能在並行流且Collector不具有CONCURRENT   時執行的  )
4. 在容器上執行一個可選的最終轉換 (finisher())     
     (非必然運行  中間結果與最終結果類型是否一致決定是否運行 IDENTITY_FINISH用來標誌  )  
 
 

屬性特徵字段


特徵值是Collector的特徵值,用於描述Collecto自己r的,不是其餘含義
 Set<Characteristics> characteristics()  方法能夠訪問
Collector.Characteristics  CONCURRENT 
表示中間結果只有一個,即便在並行流的狀況下
因此只有在並行流且收集器不具有CONCURRENT特性時,combiner方法返回的lambda表達式纔會執行
若是收集器沒有標爲UNORDERED,那它僅在用於無序數據源時才能夠並行歸約
 
Collector.Characteristics  UNORDERED
表示不承諾按照操做順序排列
Collector.Characteristics  IDENTITY_FINISH
表示中間結果容器類型與最終結果類型一致,此時finiser方法不會被調用
 
靜態工廠方法
根據提供的給定條件建立 Collector
image_5b7bb60d_c4d
 

Collector  就是歸約運算操做的一種抽象


image_5b7bb60d_72cc
首先要理解歸約reduce的含義  也就是概括轉換成另一種形式
想要進行歸約運算,你先給出一個初始容器,做爲中間結果容器
而後再給出迭代運算邏輯 也就是要如何歸約  歸約的邏輯  就是在這裏 結果計算到中間結果容器中
針對於並行計算還須要一個合併的方式
中間結果確定是爲了方便計算,若是你最終想要的不是這種類型,我還能夠給你轉換下
 

Collector用 類型TAR 和四個方法將歸約的過程邏輯化

T - 輸入類型
A - 在收集過程當中用於累積部分結果的對象類型
R - 返回類型  
Supplier<A> supplier();  因此此方法提供了一個保存中間結果的對象 類型是A
BiConsumer<A, T> accumulator();  不斷迭代運算操做結果累計到中間結果上 類型爲A   流類型爲T
Function<A, R> finisher();  最終的結果爲A  還要根據實際狀況是否轉換爲R
BinaryOperator<A> combiner(); 用於合併計算
 

 

Collector工廠Collectors


image_5b7bb60d_2a98
提供了Collector的一些經常使用實現  好比

 

// 獲取全部的name轉換到List<String>中 List<String> list = people.stream().map(Person::getName).collect(Collectors.toList()); // 獲取全部的name轉換到Set<String>中 Set<String> set = people.stream().map(Person::getName).collect(Collectors.toCollection(TreeSet::new));
// 元素轉換爲String 而且將他們經過", " 鏈接起來 String joined = things.stream() .map(Object::toString) .collect(Collectors.joining(", "));
//計算員工薪水之和 int total = employees.stream() .collect(Collectors.summingInt(Employee::getSalary)));
// 按照部門對員工進行分組 Map<Department, List<Employee>> byDept = employees.stream() .collect(Collectors.groupingBy(Employee::getDepartment));
// 計算部門薪資和 Map<Department, Integer> totalByDept = employees.stream() .collect(Collectors.groupingBy(Employee::getDepartment, Collectors.summingInt(Employee::getSalary)));
// 按照成績是否經過把學生分爲兩組 Map<Boolean, List<Student>> passingFailing = students.stream() .collect(Collectors.partitioningBy(s -> s.getGrade() >= PASS_THRESHOLD));
Collectors 中有一個靜態內部類CollectorImpl  實現了CollectorImpl
預置的一些收集器都是經過CollectorImpl  返回的
/** * Simple implementation class for {@code Collector}. * * @param <T> the type of elements to be collected * @param <R> the type of the result */
static class CollectorImpl<T, A, R> implements Collector<T, A, R> { private final Supplier<A> supplier; private final BiConsumer<A, T> accumulator; private final BinaryOperator<A> combiner; private final Function<A, R> finisher; private final Set<Characteristics> characteristics;
CollectorImpl(Supplier
<A> supplier, BiConsumer<A, T> accumulator, BinaryOperator<A> combiner, Function<A,R> finisher, Set<Characteristics> characteristics) { this.supplier = supplier; this.accumulator = accumulator; this.combiner = combiner; this.finisher = finisher; this.characteristics = characteristics; } CollectorImpl(Supplier<A> supplier, BiConsumer<A, T> accumulator, BinaryOperator<A> combiner, Set<Characteristics> characteristics) { this(supplier, accumulator, combiner, castingIdentity(), characteristics); } @Override public BiConsumer<A, T> accumulator() { return accumulator; } @Override public Supplier<A> supplier() { return supplier; } @Override public BinaryOperator<A> combiner() { return combiner; } @Override public Function<A, R> finisher() { return finisher; } @Override public Set<Characteristics> characteristics() { return characteristics; } }

 

Collectors中內置的  關於Collector  characteristics  特性的組合值
image_5b7bb60e_3f50
 
 
看一個例子
Collector<T, ?, List<T>> toList() { return new CollectorImpl<>( (Supplier<List<T>>) ArrayList::new, List::add, (left, right) -> { left.addAll(right); return left; }, CH_ID); }

 

TAR分別是 T ?  List<T>  也就是處理元素爲T類型 返回結果爲List<T>  中間結果隨意
ArrayList::new  返回List<T>  做爲中間結果,顯然,跟返回結果同樣,不須要調用finisher了
歸約方式爲 使用List.add方法不斷地將集合中的元素添加到中間結果中
合併方式爲直接將一個List addAll到另外一個list  而且返回最終結果
由於不須要調用finisher  設置下特徵 CH_ID
 
因此說只要按規矩實現了四個方法以及設置characteristics 就能夠實現一個Collector
 
你可使用Stream中
image_5b7bb60e_1304
調用Collectors 提供的一些Collector  或者你本身定義的
你還可使用Stream中
image_5b7bb60e_4fc2
直接傳遞參數,顯然並非很直觀 建議能不用就別用了 
相關文章
相關標籤/搜索