list.stream().map(i -> i * 2).collect(Collectors.toList);安全
Collector是由四個功能指定一塊兒工做以累加條目到一個可變的結果容器,和任選地執行該結果的最終變換:併發
建立一個新的結果容器: supplier()
app
結合有新的數據元素到結果容器: accumulator()
jvm
accumulator()
一次兩個結果的容器組合成一個: combiner()
ide
combiner的邏輯:假設有1,2,3,4號線程處理,返回了4個結果,有可能出現的組合方式是:函數
finisher()
Characteristics
是一個枚舉類,來判斷結果集合容器是否支持並行操做。爲了保證併發安全,保證並行和串行執行的結果一致,收集器函數必須知足兩個條件this
同一性(identity):線程
a == combiner.apply(a, supplier.get())
結合性(associativity):分割計算必須獲得一個等價的結果code
UNORDERED
,則只須要兩個結果集中的內容是相同的,無視順序。實現基於匯聚操做的Collector ,如Stream.collect(Collector) ,必須遵循如下限制:對象
accumulator()
的第一個參數,以及傳遞給combiner()
的兩個參數,並傳遞給finisher()
的參數(這3種其實都是結果容器的類型),每一次的結果容器類型必須和上一次的結果容器類型相同。accumulator()
、combiner()
、finisher()
的結果相關的任何操做。finisher()
,相同的對象沒有從函數返回的(說明你使用了新的結果容器,jdk認爲以前的結果容器已經被使用完成了),它永遠不會再使用。combiner()
或finisher()
,說明accumulator()
已經被執行完成了,則不會再調用它。supplier()
、accumulator()
、combiner()
的返回必須串行線程限制,保證不會有其餘線程可以獲取。 經過線程封閉來實現,Collector就不須要實現任何額外的同步。 減小執行必須管理輸入正確分區,該分區在隔離處理,並在combine
完成後,才執行finsher
操做。accumulator()
。而且僅當UNORDERED
時,才應該使用這種併發縮減。(爲了線程安全,此時的容器應該是線程安全的)收集器自己是支持compose(組合)
,例如計算出員工工資總和的一個收集器,能夠被經過分組的組合再次使用。
Collector<Employee, ?, Integer> summingSalaries
= Collectors.summingInt(Employee::getSalary))
Collector<Employee, ?, Map<Department, Integer>> summingSalariesByDept
= Collectors.groupingBy(Employee::getDepartment, summingSalaries);
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;
default Comparator<T> reversed() {
return Collections.reverseOrder(this);
}
Student student1 = new Student("A", 90);
Student student2 = new Student("B", 80);
Student student3 = new Student("C", 100);
Student student4 = new Student("D", 90);
Student student5 = new Student("D", 70);
List<Student> list = Arrays.asList(student1, student2, student3, student4, student5);
Map<String, Student> map2 = list.stream().collect(Collectors.groupingBy(Student::getName,
Collectors.collectingAndThen(Collectors.minBy(Comparator.comparingInt(Student::getScore)), Optional::get)));
System.out.println(map2);
public class MySetCollector<T> implements Collector<T, Set<T>, Set<T>> {
@Override
public Supplier<Set<T>> supplier() {
System.out.println("supplier invoked");
return HashSet::new;
}
@Override
public BiConsumer<Set<T>, T> accumulator() {
System.out.println("accumulator invoked");
return Set::add;
}
@Override
public BinaryOperator<Set<T>> combiner() {
System.out.println("combiner invoked");
return (set1, set2) -> {
set1.addAll(set2);
return set1;
};
}
@Override
public Function<Set<T>, Set<T>> finisher() {
System.out.println("finisher invoked");
return set -> set;
}
@Override
public Set<Characteristics> characteristics() {
System.out.println("characteristics invoked");
return Collections.unmodifiableSet(EnumSet.of(Characteristics.IDENTITY_FINISH, Characteristics.UNORDERED));
}
}
supplier
:構造中間結果容器accmulator
:將流中的元素累加到中間結果容器中combiner
:將fork的中間結果容器join起來finisher
:若是中間結果容器和須要返回的結果容器不一樣,須要finisher
內實現轉化代碼characteristics
:定義當前收集器的特性
CONCURRENT
:中間結果容器線程安全,支持併發寫入。若是設置了CONCURRENT,收集器將放棄forkjoin模式,直接讓線程操做同一個中間結果容器。
CONCURRENT
屬性,若是出現安全性問題(即併發修改),jvm將會拋出ConcurrentModificationException
。實現自定義收集器,必須override上面這5個方法: 自定義收集器實現 -------- 源碼實現上應該是當comparingInt的返回結果爲0時,纔會繼續調用thenComparing 先根據name排序,若是name相等,則根據分數排序。 thenCoparing能夠理解爲次級排序 ### thenComparing 默認比較器爲升序排序,若是調用reversed,則返回的爲倒序排序 ### reversed Comparator是一個函數式接口,只有一個抽象方法`int compare(T o1, T o2);`,其他提供了不少默認方法。 * 返回-1,則表示o1比o2小。 * 返回 0,則表示o1和o2相等 * 返回1,則表示o1比o2大 Comparator是一個比較器,從JDK1.2時候開始提供。其中最重要的方法應該是`int compare(T o1, T o2);`方法。 Comparator ---------- Collectors是一個收集器工廠,爲開發者提供一些經常使用的收集器和收集器方法。Collectors的收集器是私有的,因此沒法直接實例化這個工廠。 `Collectors`是`Collector`接口的官方惟一實現類。`Collecotrs`維護了一個CollectorImpl的內部類 Collectors ---------- * `CONCURRENT`:表示這個收集器是能夠併發的。 * 這裏的併發和parallelStream不一樣,parallStream是經過建立多個結果容器,再經過combiner合併到一塊兒。 * 而這個Concurrent表示,同一個結果容器支持多個線程同時調用。(這個容器須要線程安全的) * `UNORDERED`:收集操做並不保證與輸入元素順序一致。 * `IDENTITY_FINISH`:若是中間的結果容器類型就是返回容器的類型,這時候才能夠配置,finsher函數會直接將結果類型轉化爲傳入的參數類型 #### Characteristics