學習的時候,官方文檔是最重要的.html
及其重要的內容咱們不只要知道stream用,要知道爲何這麼用,還要知道底層是怎麼去實現的.java
--我的註釋:今後看出,雖然新的jdk版本對開發人員提供了很大的遍歷,可是從底層角度來講,實現確實是很是複雜的.
--對外提供很簡單的接口使用. (必定是框架給封裝到底層了,因此你才用着簡單.)api
遇到問題,可以從底層深刻解決問題.數組
學習一門技術的時候,先學會用,而後去挖掘深層次的內容(底層代碼和運做方式).多線程
引入:Example.併發
public class StudentTest1 { public static void main(String[] args) { Student student1 = new Student("zhangsan", 80); Student student2 = new Student("lisi", 90); Student student3 = new Student("wangwu", 100); Student student4 = new Student("zhaoliu", 90); List<Student> students = Arrays.asList(student1, student2, student3, student4); //collect()方法深刻源碼詳解 //op1:集合轉換爲stream, 而後stream轉換爲List List<Student> students1 = students.stream().collect(Collectors.toList()); students1.forEach(System.out::println); System.out.println("----------"); System.out.println("count: "+ students.stream().collect(counting()));//Collectors類提供的counting()方法 System.out.println("count: "+ students.stream().count()); //stream提供的方法 , 底層實現 mapToLong()->sum //當jdk底層提供有通用的方法和具體的實現方法,越具體的越好. } }
靜態導入(直接導入指定Java類中實現的方法)app
import static java.util.stream.Collectors.*;
題外話:雖然JDK提供了不少Collector的實現,可是不少人僅停留在使用階段.框架
咱們此次一行一行的讀javadoc. 由於真的很重要.ide
/** * A <a href="package-summary.html#Reduction">mutable reduction operation</a> that * accumulates input elements into a mutable result container, optionally transforming * the accumulated result into a final representation after all input elements * have been processed. Reduction operations can be performed either sequentially * or in parallel. 一個可變的匯聚操做.將輸入元素累積到可變的結果容器當中.它會在全部元素都處理完畢後,將累積以後的結果轉換成一個最終的表示(這是一個可選操做).匯聚操做支持串行和並行兩種方式執行. --如 ArrayList:就是一個可變的容器. --支持並行操做:確保數據不會錯,線程能夠併發.很難.另外並非說並行必定比串行要快,由於並行是有額外開銷的. * * <p>Examples of mutable reduction operations include: * accumulating elements into a {@code Collection}; concatenating * strings using a {@code StringBuilder}; computing summary information about * elements such as sum, min, max, or average; computing "pivot table" summaries * such as "maximum valued transaction by seller", etc. The class {@link Collectors} * provides implementations of many common mutable reductions. 可變的reduction(匯聚)操做包括:將元素累積到集合當中,使用StringBuilder將字符串給拼在一塊兒,計算關於元素的sum,min,max or average等,計算數據透視圖計算:如根據銷售商獲取最大銷售額等.這個Collectors類,提供了大量的可變匯聚的實現. -- Collectors自己其實是一個工廠. * * <p>A {@code Collector} is specified by four functions that work together to * accumulate entries into a mutable result container, and optionally perform * a final transform on the result. They are: <ul> * <li>creation of a new result container ({@link #supplier()})</li> * <li>incorporating a new data element into a result container ({@link #accumulator()})</li> * <li>combining two result containers into one ({@link #combiner()})</li> * <li>performing an optional final transform on the container ({@link #finisher()})</li> * </ul> 一個Collector是由4個函數組成的,能夠對結果進行一個最終的轉化. 4個方法分別是: 1.建立一個新的接結果容器 <supplier()> new 2.將新的數據元素給合併到一個結果容器中.<accumulator()> add 3.將兩個結果容器合併成一個.<combiner()> + 4.將中間的累積類型,轉換成結果類型. <finisher()> result 每一個方法都會返回一個函數式皆苦. --學習的時候,官方文檔是最重要的. * * <p>Collectors also have a set of characteristics, such as * {@link Characteristics#CONCURRENT}, that provide hints that can be used by a * reduction implementation to provide better performance. Collectors 還會返回這麼一個集合 Characteristics#CONCURRENT. (也就是這個類中的枚舉類) * * <p>A sequential implementation of a reduction using a collector would * create a single result container using the supplier function, and invoke the * accumulator function once for each input element. * A parallel implementation * would partition the input, create a result container for each partition, * accumulate the contents of each partition into a subresult for that partition, * and then use the combiner function to merge the subresults into a combined * result. 一個匯聚操做串行的實現,會建立一個惟一的一個結果容器.使用<Supplier>函數. 每個輸入元素都會調用累積函數(accumulator())一次. 一個並行的實現,將會對輸入進行分區,分紅多個區域,每一次分區都會建立一個結果容器,而後函數.累積每個結果容器的內容區內造成一個,而後經過comtainer()給合併成一個. -- 解釋: combiner函數,假若有4個線程同時去執行,那麼就會生成4個部分結果. 結果分別是:1.2.3.4 多是: 1.2 -> 5 5.3 -> 6 6.4 -> 7 這5.6.7新建立的集合,就叫作 新的結果容器 也多是: 1.2 -> 1+2 (新的一個) 1.3 -> 1(新的一個) 這種新的摺疊後的,叫作摺疊成一個參數容器. * * <p>To ensure that sequential and parallel executions produce equivalent * results, the collector functions must satisfy an <em>identity</em> and an * <a href="package-summary.html#Associativity">associativity</a> constraints. 爲了確保串行與並行得到等價的結果. collector(收集器)的函數必須知足2個條件. 1. identity: 同一性 2. Associativity :結合性 * * <p>The identity constraint says that for any partially accumulated result, * combining it with an empty result container must produce an equivalent * result. That is, for a partially accumulated result {@code a} that is the * result of any series of accumulator and combiner invocations, {@code a} must * be equivalent to {@code combiner.apply(a, supplier.get())}. 同一性是說:針對於任何部分累積的結果來講,將他與一個空的容器融合,必須會生成一個等價的結果.等價於部分的累積結果. 也就是說對於一個部分的累積結果a,對於任何一條線上的combiner invocations. a == combiner.apply(a, supplier.get()) supplier.get() ,獲取一個空的結果容器. 而後將a與空的結果容器容器. 保證a == (融合等式) . 這個特性就是:同一性. --部分累積的結果:是在流程中產生的中間結果. --解釋上述等式爲何成立:a是線程某一個分支獲得的部分結果. 後面的是調用BiarnyOperator.apply() (List<String> list1,List<String> list2)->{list1.addAll(list2);return list1;} 這個相似於以前說的: 將兩個結果集摺疊到同一個容器.而後返回來第一個結果的融合. * * <p>The associativity constraint says that splitting the computation must * produce an equivalent result. That is, for any input elements {@code t1} * and {@code t2}, the results {@code r1} and {@code r2} in the computation * below must be equivalent: 結合性是說:分割執行的時候,也必須產生相同的結果.每一份處理完以後,也獲得相應的結果. * <pre>{@code * A a1 = supplier.get();//獲取結果容器 a1. * accumulator.accept(a1, t1); //a1:每一次累積的中間結果, t1:流中下一個待累積的元素. * accumulator.accept(a1, t2); //t1->a1, a1已經有東西. 而後 t2->t1 = r1 (也就是下一步) * R r1 = finisher.apply(a1); // result without splitting * * A a2 = supplier.get(); //另一個線程 * accumulator.accept(a2, t1); //兩個結果集轉換成中間結果. * A a3 = supplier.get(); //第三個線程 * accumulator.accept(a3, t2); //兩個中間結果轉換成最終結果. * R r2 = finisher.apply(combiner.apply(a2, a3)); // result with splitting * } </pre> 因此要保證:不管是單線程,仍是多線程(串行和並行)的結果都要是同樣的. 這就是所謂的:結合性. --我的註釋:今後看出,雖然新的jdk版本對開發人員提供了很大的遍歷,可是從底層角度來講,實現確實是很是複雜的. --對外提供很簡單的接口使用. (必定是框架給封裝到底層了,因此你才用着簡單.) * * <p>For collectors that do not have the {@code UNORDERED} characteristic, * two accumulated results {@code a1} and {@code a2} are equivalent if * {@code finisher.apply(a1).equals(finisher.apply(a2))}. For unordered * collectors, equivalence is relaxed to allow for non-equality related to * differences in order. (For example, an unordered collector that accumulated * elements to a {@code List} would consider two lists equivalent if they * contained the same elements, ignoring order.) 對於一個不包含無序的收集器來講, a1 和 a2是等價的. 條件:finisher.apply(a1).equals(finisher.apply(a2) 對於無序的收集器來講:這種等價性就沒有那麼嚴格了,它會考慮到順序上的區別所對應的不相等性. * * <p>Libraries that implement reduction based on {@code Collector}, such as * {@link Stream#collect(Collector)}, must adhere to the following constraints: 基於Collector 去實現匯聚(reduction)操做的這種庫, 必須遵照以下的約定. - 註釋:匯聚其實有多種實現. 如Collectors中的reducting(). 如Stream接口中有三種reduce()重載的方法. 這兩個有很大的本質的差異: (注意單線程和多線程狀況下的影響.) reduce:要求不可變性 Collectors收集器方式:可變的結果容器. * <ul> * <li>The first argument passed to the accumulator function, both * arguments passed to the combiner function, and the argument passed to the * finisher function must be the result of a previous invocation of the * result supplier, accumulator, or combiner functions.</li> 1. 傳遞給accumulate函數的參數,以及給Combiner的兩個參數,以及finisher函數的參數, 他們必須是 這幾個supplier, accumulator, or combiner 函數函數上一次調用的結果(泛型-T). * <li>The implementation should not do anything with the result of any of * the result supplier, accumulator, or combiner functions other than to * pass them again to the accumulator, combiner, or finisher functions, * or return them to the caller of the reduction operation.</li> 2. 實現不該該對, 生成的 --- 結果 作任何的事情. 除了將他們再傳給下一個函數. (中間不要作任何的操做,不然確定是紊亂的.) * <li>If a result is passed to the combiner or finisher * function, and the same object is not returned from that function, it is * never used again.</li> 3.若是一個結果被傳遞給combiner或者finisher函數,相同的對象並無從函數裏面返回, 那麼他們不再會被使用了.(表示已經被用完了.) * <li>Once a result is passed to the combiner or finisher function, it * is never passed to the accumulator function again.</li> 4.一個函數若是被執行給了combiner或者finisher函數以後,它不再會被accumulate函數調用了. (就是說,若是被結束函數執行完了. 就不會再被中間操做了.) * <li>For non-concurrent collectors, any result returned from the result * supplier, accumulator, or combiner functions must be serially * thread-confined. This enables collection to occur in parallel without * the {@code Collector} needing to implement any additional synchronization. * The reduction implementation must manage that the input is properly * partitioned, that partitions are processed in isolation, and combining * happens only after accumulation is complete.</li> 5. 對於非併發的收集起來講.從supplier, accumulator, or combiner任何的結果返回必定是被限定在當前的線程了. 因此能夠被用在並行的操做了. reduction的操做必須被確保被正確的分析了,4個線程,被分爲4個區,不會相互干擾,再都執行完畢以後,再講中間容器進行融合.造成最終結果返回. * <li>For concurrent collectors, an implementation is free to (but not * required to) implement reduction concurrently. A concurrent reduction * is one where the accumulator function is called concurrently from * multiple threads, using the same concurrently-modifiable result container, * rather than keeping the result isolated during accumulation. 6.對於併發的收集器,實現能夠自由的選擇. 和上面的5相對於. 在累積階段不須要保持獨立性. * A concurrent reduction should only be applied if the collector has the * {@link Characteristics#UNORDERED} characteristics or if the * originating data is unordered.</li> 一個併發的,在這個時候必定會被使用; 無序的. --到此結束,重要的 概念基本上已經介紹完畢了. * </ul> * * <p>In addition to the predefined implementations in {@link Collectors}, the * static factory methods {@link #of(Supplier, BiConsumer, BinaryOperator, Characteristics...)} * can be used to construct collectors. For example, you could create a collector * that accumulates widgets into a {@code TreeSet} with: * * <pre>{@code * Collector<Widget, ?, TreeSet<Widget>> intoSet = * Collector.of(TreeSet::new, TreeSet::add, * (left, right) -> { left.addAll(right); return left; }); * }</pre> 使用.三個參數構造的 of 方法,() 三個參數 1.結果容器 2.將數據元素累積添加到結果容器 3.返回結果容器.(此處使用TreeSet) * * (This behavior is also implemented by the predefined collector.預約義的Collector. * {@link Collectors#toCollection(Supplier)}). * * @apiNote * Performing a reduction operation with a {@code Collector} should produce a * result equivalent to: * <pre>{@code * R container = collector.supplier().get(); * for (T t : data) * collector.accumulator().accept(container, t); * return collector.finisher().apply(container); * }</pre> 上述:匯聚容器的實現過程. 1.建立一個容器 2.累加到容器 3.返回結果容器. * * <p>However, the library is free to partition the input, perform the reduction * on the partitions, and then use the combiner function to combine the partial * results to achieve a parallel reduction. (Depending on the specific reduction * operation, this may perform better or worse, depending on the relative cost * of the accumulator and combiner functions.) 性能的好壞:取決於實際狀況. (並行不必定比串行性能高.) * * <p>Collectors are designed to be <em>composed</em>; many of the methods * in {@link Collectors} are functions that take a collector and produce * a new collector. For example, given the following collector that computes * the sum of the salaries of a stream of employees: 收集器自己被設計成能夠組合的. 也就是說收集器自己的組合.例以下. * * <pre>{@code * Collector<Employee, ?, Integer> summingSalaries * = Collectors.summingInt(Employee::getSalary)) * }</pre> Collector(),三個參數. * * If we wanted to create a collector to tabulate the sum of salaries by * department, we could reuse the "sum of salaries" logic using * {@link Collectors#groupingBy(Function, Collector)}: 若是想建立一個組合的容器. 就是以前用的groupingBy()的分類函數.以下例子. * * <pre>{@code * Collector<Employee, ?, Map<Department, Integer>> summingSalariesByDept * = Collectors.groupingBy(Employee::getDepartment, summingSalaries); * }</pre> 分組->求和 分組->求和 二級分組. * * @see Stream#collect(Collector) * @see Collectors * * @param <T> the type of input elements to the reduction operation * @param <A> the mutable accumulation type of the reduction operation (often * hidden as an implementation detail) * @param <R> the result type of the reduction operation * @since 1.8 */
理解到這裏,受益不淺.函數
* @param <T> the type of input elements to the reduction operation * @param <A> the mutable accumulation type of the reduction operation (often * hidden as an implementation detail) * @param <R> the result type of the reduction operatio
/** * A function that creates and returns a new mutable result container. * 建立一個新的可變結果容器.返回 Supplier函數式接口. * @return a function which returns a new, mutable result container 泛型 - A : 可變容器的類型. */ Supplier<A> supplier();
/** * A function that folds a value into a mutable result container. * 將一個新的元素數據元素摺疊(累加)到一個結果容器當中. 返回值爲 BiConsumer函數式接口 * @return a function which folds a value into a mutable result container 泛型-A:返回的中間容器的類型(結果類型) 泛型-T:流中待處理的下一個元素的類型.(源類型) */ BiConsumer<A, T> accumulator();
/** 和並行流緊密相關. * A function that accepts two partial results and merges them. The * combiner function may fold state from one argument into the other and * return that, or may return a new result container. * 接收兩個部分結果,而後給合併起來.將結果狀態從一個參數轉換成另外一個參數,或者返回一個新的結果容器....*(有點難理解.) 返回一個組合的操做符函數接口類. -- 解釋: combiner函數,假若有4個線程同時去執行,那麼就會生成4個部分結果. 結果分別是:1.2.3.4 多是: 1.2 -> 5 5.3 -> 6 6.4 -> 7 這5.6.7新建立的集合,就叫作 新的結果容器 也多是: 1.2 -> 1+2 (新的一個) 1.3 -> 1(新的一個) 這種新的摺疊後的,叫作摺疊成一個參數容器. 因此:combiner 是 專門用在 並行流中的. * @return a function which combines two partial results into a combined * result 泛型-A: (結果容器類型.中間結果容器的類型.) TTT */ BinaryOperator<A> combiner();
/** * Perform the final transformation from the intermediate accumulation type * {@code A} to the final result type {@code R}. *接收一箇中間對象,返回另一個結果.對象. * <p>If the characteristic {@code IDENTITY_TRANSFORM} is * set, this function may be presumed to be an identity transform with an * unchecked cast from {@code A} to {@code R}. *若是這個特性被設置值了的話,..... 返回一個Function接口類型. * @return a function which transforms the intermediate result to the final * result 泛型-A :結果容器類型 泛型-R : 最終要使用的類型.(最終返回的結果的類型.) */ Function<A, R> finisher();
/** * Characteristics indicating properties of a {@code Collector}, which can * be used to optimize reduction implementations. 這個類中顯示的這些屬性,被用做:優化匯聚的實現. --解釋: 類的做用:告訴收集器,我能夠對這個目標進行怎麼樣的執行動做. */ enum Characteristics { /** * Indicates that this collector is <em>concurrent</em>, meaning that * the result container can support the accumulator function being * called concurrently with the same result container from multiple * threads. * * <p>If a {@code CONCURRENT} collector is not also {@code UNORDERED}, * then it should only be evaluated concurrently if applied to an * unordered data source. */ CONCURRENT,//表示能夠支持併發. /** * Indicates that the collection operation does not commit to preserving * the encounter order of input elements. (This might be true if the * result container has no intrinsic order, such as a {@link Set}.) */ UNORDERED, /** * Indicates that the finisher function is the identity function and * can be elided. If set, it must be the case that an unchecked cast * from A to R will succeed. */ IDENTITY_FINISH }