Java SE 8 中引入了這樣一個庫: java.util.stream 包,它有助於爲各類數據來源的批量操做創建簡明的、聲明性的表達式。它是一個精心設計的庫,充分利用了Lambda特性,能夠將 Streams 視爲 Java 中第一個充分利用了Lambda表達式的強大功能的庫。java
清單1:原來計算一個列表中除去1的總和的代碼:編程
List<Integer> list = Arrays.asList(1,2,3,4,5); int sum = 0; for(Integer i: list){ if(i == 1){ continue; } sum+=i; }
清單2:使用Stream進行計算的代碼:數組
List<Integer> list = Arrays.asList(1,2,3,4,5); int sum=list.stream().filter(t->t!=1).mapToInt(t->t).sum();
能夠發現,使用Stream進行計算的代碼更加簡潔,而且可讀性更強數據結構
流的關注點不是數據,而是計算,流具備很強的數據聚合、彙總能力。一個流管道包含一個流來源、0 或多箇中間操做,以及一個終止操做。
使用流進行數據計算能夠大體分爲三個步驟:
一、由數據源構建流管道,即建立一個Stream
二、執行中間流操做
三、執行終止流操做app
構建流管道:ide
Collection.stream() 使用一個集合的元素建立一個流。 Stream.of(T...) 使用傳遞給工廠方法的參數建立一個流。 Stream.of(T[]) 使用一個數組的元素建立一個流。 Stream.empty() 建立一個空流。 Stream.iterate(T first, BinaryOperator<T> f) 建立一個包含序列 first, f(first), f(f(first)), ... 的無限流 Stream.iterate(T first, Predicate<T> test, BinaryOperator<T> f) (僅限 Java 9)相似於 Stream.iterate(T first, BinaryOperator<T> f),但流在測試預期返回 false 的第一個元素上終止。 Stream.generate(Supplier<T> f) 使用一個生成器函數建立一個無限流。 IntStream.range(lower, upper) 建立一個由下限到上限(不含)之間的元素組成的 IntStream。 IntStream.rangeClosed(lower, upper) 建立一個由下限到上限(含)之間的元素組成的 IntStream。 BufferedReader.lines() 建立一個有來自 BufferedReader 的行組成的流。 BitSet.stream() 建立一個由 BitSet 中的設置位的索引組成的 IntStream。 Stream.chars() 建立一個與 String 中的字符對應的 IntStream。
中間流操做:函數
filter(Predicate<T>) 與預期匹配的流的元素 map(Function<T, U>) 將提供的函數應用於流的元素的結果 flatMap(Function<T, Stream<U>> 將提供的流處理函數應用於流元素後得到的流元素 distinct() 已刪除了重複的流元素 sorted() 按天然順序排序的流元素 Sorted(Comparator<T>) 按提供的比較符排序的流元素 limit(long) 截斷至所提供長度的流元素 skip(long) 丟棄了前 N 個元素的流元素 takeWhile(Predicate<T>) (僅限 Java 9)在第一個提供的預期不是 true 的元素處階段的流元素 dropWhile(Predicate<T>) (僅限 Java 9)丟棄了所提供的預期爲 true 的初始元素分段的流元素
清單3:返回年齡小於22歲且身高由低到高排名在11-20名的同窗的名字測試
List<String> names=list.stream().sorted(Comparator.comparing(t->t.getHeight())).filter(t->t.getAge()< 22).map(t->t.getName()).skip(10).limit(10).collect(Collectors.toList());
終止流操做:設計
forEach(Consumer<T> action) 將提供的操做應用於流的每一個元素。 toArray() 使用流的元素建立一個數組。 reduce(...) 將流的元素聚合爲一個彙總值。 collect(...) 將流的元素聚合到一個彙總結果容器中。 min(Comparator<T>) 經過比較符返回流的最小元素。 max(Comparator<T>) 經過比較符返回流的最大元素。 count() 返回流的大小。 {any,all,none}Match(Predicate<T>) 返回流的任何/全部元素是否與提供的預期相匹配。 findFirst() 返回流的第一個元素(若是有)。 findAny() 返回流的任何元素(若是有)。
聚合操做Stream.reduce()能夠將元素序列聚合到該類型的單個元素值。Stream庫中有多種reduce()方法,包括瞭如下兩種:
Optional<T> reduce(BinaryOperator<T> op)
T reduce(T identity, BinaryOperator<T> op)code
Reduction Operation是一種來自函數編程的技術,它抽象化了許多不一樣的操做。給定一個類型爲 T,包含 n 個元素的非空數列 (x1, x2, ..., xn) 和 T 上的二元運算符(在這裏表示爲&),reduction opreation 被定義爲:(x1&x2&x3...&xn)
二元運算符&須要知足結合性條件:即 ((a&b)&c)==(a&(b&c)),並不須要知足交換性
Optional<T> reduce(BinaryOperator<T> op):只須要肯定二元運算符即定義reduction operation的具體操做便可。
清單5:計算總和
int sum = Stream.of(1,2,3,4,5).reduce((a,b)->a+b;).get();
清單6:計算最大值
int max = Stream.of(1,2,3,4,5).reduce(Math::max).get();
T reduce(T identity, BinaryOperator<T> op):使用這個方法時還須要提供一個identity初始值
清單7:字符串串聯:
String string = strings.stream().reduce("",String::concat);
Stream.reduce操做是經過某個鏈接動做將全部元素彙總成一個彙總結果,好比獲取數列的和或它的最大值。可是有時咱們並不須要單個彙總值;您想將結果組織爲相似 List 或 Map 的數據結構,或者將它彙總爲多個彙總值。在這種狀況下,可使用collect()方法。
它接受如下 3 個參數:
<R> collect(Supplier<R> resultSupplier, BiConsumer<R, T> accumulator, BiConsumer<R, R> combiner)
Supplier<R> resultSupplier:一種生成空結果容器的途徑
BiConsumer<R, T> accumulator:一種將新元素合併到結果容器中的途徑
BiConsumer<R, R> combiner:一種合併兩個結果容器的途徑
清單8:
List<String> names=list.stream().filter(t->t.getAge()>20).map(t->t.getName()).collect(ArrayList::new,ArrayList::add,ArrayList::addAll);
ArrayList::new 建立一個ArrayList的空容器
ArrayList::add 將新元素添加到結果容器中
ArrayList::addAll 合併兩個ArrayList容器
Stream同時還有這樣一個collect()方法:
<R, A> R collect(Collector<? super T, A, R> collector);
Collector做爲參數傳入,配合Collectors使用開發更加簡便,清單8能夠直接調用Collectors.toList()方法
List<String> names=list.stream().filter(t->t.getAge()>20).map(t->t.getName()).collect(Collectors.toList());
Collectors 類常見的聚合操做
toList() 將元素收集到一個 List 中。 toSet() 將元素收集到一個 Set 中。 toCollection(Supplier<Collection>) 將元素收集到一個特定類型的 Collection 中。 toMap(Function<T, K>, Function<T, V>) 將元素收集到一個 Map 中,依據提供的映射函數將元素轉換爲鍵值。 summingInt(ToIntFunction<T>) 計算將提供的 int 值映射函數應用於每一個元素(以及 long 和 double 版本)的結果的總和。 summarizingInt(ToIntFunction<T>) 計算將提供的 int 值映射函數應用於每一個元素(以及 long 和 double 版本)的結果的 sum、min、max、count 和 average。 reducing() 向元素應用縮減(一般用做下游收集器,好比用於 groupingBy)(各類版本)。 partitioningBy(Predicate<T>) 將元素分爲兩組:爲其保留了提供的預期的組和未保留預期的組。 partitioningBy(Predicate<T>, Collector) 將元素分區,使用指定的下游收集器處理每一個分區。 groupingBy(Function<T,U>) 將元素分組到一個 Map 中,其中的鍵是所提供的應用於流元素的函數,值是共享該鍵的元素列表。 groupingBy(Function<T,U>, Collector) 將元素分組,使用指定的下游收集器來處理與每一個組有關聯的值。 minBy(BinaryOperator<T>) 計算元素的最小值(與 maxBy() 相同)。 mapping(Function<T,U>, Collector) 將提供的映射函數應用於每一個元素,並使用指定的下游收集器(一般用做下游收集器自己,好比用於 groupingBy)進行處理。 joining() 假設元素爲 String 類型,將這些元素聯結到一個字符串中(或許使用分隔符、前綴和後綴)。 counting() 計算元素數量。(一般用做下游收集器。)
這裏主要介紹一下Collectors.groupingBy(),它主要用於對元素的分組操做,同時它也能夠經過結合下游收集器實現對元素更加複雜,更加細緻的分組操做
一、groupingBy(Function<T,U>) 將元素分組到一個 Map 中,其中的鍵是所提供的應用於流元素的函數,值是共享該鍵的元素列表。
使用Student.age做爲Map的key,value則是List<Student>
Map<Integer,List<Student>> map=list.stream().collect(Collectors.groupingBy(Student::getAge));
二、groupingBy(Function<T,U>, Collector) 將元素分組,使用指定的下游收集器來處理與每一個組有關聯的值。
將Student.age做爲Map的key,只保留各年齡段身高最高的student
Map<Integer,Optional<Student>> map=list.stream().collect(Collectors.groupingBy(Student::getAge,Collectors.maxBy(Comparator.comparing(Student::getHeight))));
對於順序執行,Stream構造了一個 Consumer對象鏈,其結構與管道結構相符。其中每一個 Consumer 對象知道下一個階段;當它收到一個元素(或被告知沒有更多元素)時,它會將 0 或多個元素髮送到鏈中的下一個階段。例如,與 filter() 階段有關聯的 Consumer 將過濾器謂詞應用於輸入元素,並將它發送或不發送到下一個階段;與 map() 階段有關聯的 Consumer 將映射函數應用於輸入元素,並將結果發送到下一個階段。與有狀態操做(好比 sorted())有關聯的 Consumer 會緩衝元素,直到它看到輸入的末尾,而後將排序的數據發送到下一個階段。Consumer對象鏈的最後一個階段將實現終止操做。