Stream
是Java 1.8版本開始提供的一個接口,主要提供對數據集合使用流的方式進行操做,流中的元素不可變且只會被消費一次,全部方法都設計成支持鏈式調用。使用Stream API能夠極大生產力,寫出高效率、乾淨、簡潔的代碼。java
Stream
提供了靜態構建方法,能夠基於不一樣的參數建立返回Stream實例
使用Collection
的子類實例調用stream()
或者parallelStream()
方法也能夠獲得Stream實例,兩個方法的區別在於後續執行Stream
其餘方法的時候是單線程仍是多線程數組
Stream<String> stringStream = Stream.of("1", "2", "3"); //無限長的偶數流 Stream<Integer> evenNumStream = Stream.iterate(0, n -> n + 2); List<String> strList = new ArrayList<>(); strList.add("1"); strList.add("2"); strList.add("3"); Stream<String> strStream = strList.stream(); Stream<String> strParallelStream = strList.parallelStream();
filter
方法用於根據指定的條件作過濾,返回符合條件的流多線程
Stream<Integer> numStream = Stream.of(-2, -1, 0, 1, 2, 3); //得到只包含正數的流,positiveNumStream -> (1,2,3) Stream<Integer> positiveNumStream = numStream.filter(num -> num > 0);
map
方法用於將流中的每一個元素執行指定的轉換邏輯,返回其餘類型元素的流app
Stream<Integer> numStream = Stream.of(-2, -1, 0, 1, 2, 3); //轉換成字符串流 Stream<String> strStream = numStream.map(String::valueOf);
這三個方法是對map
方法的封裝,返回的是官方爲各個類型單獨定義的Stream,該Stream還提供了適合各自類型的其餘操做方法ide
Stream<String> stringStream = Stream.of("-2", "-1", "0", "1", "2", "3"); IntStream intStream = stringStream.mapToInt(Integer::parseInt); LongStream longStream = stringStream.mapToLong(Long::parseLong); DoubleStream doubleStream = stringStream.mapToDouble(Double::parseDouble);
flatMap
方法用於將流中的每一個元素轉換成其餘類型元素的流,好比,當前有一個訂單(Order)列表,每一個訂單又包含多個商品(itemList),若是要獲得全部訂單的全部商品彙總,就可使用該方法,以下:this
Stream<Item> allItemStream = orderList.stream().flatMap(order -> order.itemList.stream());
這三個方法是對flatMap
方法的封裝,返回的是官方爲各個類型單獨定義的Stream,使用方法同上線程
distinct
方法用於對流中的元素去重,判斷元素是否重複使用的是equals
方法debug
Stream<Integer> numStream = Stream.of(-2, -1, 0, 0, 1, 2, 2, 3); //不重複的數字流,uniqueNumStream -> (-2, -1, 0, 1, 2, 3) Stream<Integer> uniqueNumStream = numStream.distinct();
sorted
有一個無參和一個有參的方法,用於對流中的元素進行排序。無參方法要求流中的元素必須實現Comparable
接口,否則會報java.lang.ClassCastException
異常設計
Stream<Integer> unorderedStream = Stream.of(5, 6, 32, 7, 27, 4); //按從小到大排序完成的流,orderedStream -> (4, 5, 6, 7, 27, 32) Stream<Integer> orderedStream = unorderedStream.sorted();
有參方法sorted(Comparator<? super T> comparator)
不須要元素實現Comparable
接口,經過指定的元素比較器對流內的元素進行排序code
Stream<String> unorderedStream = Stream.of("1234", "123", "12", "12345", "123456", "1"); //按字符串長度從小到大排序完成的流,orderedStream -> ("1", "12", "123", "1234", "12345", "123456") Stream<String> orderedStream = unorderedStream.sorted(Comparator.comparingInt(String::length));
peek
方法能夠不調整元素順序和數量的狀況下消費每個元素,而後產生新的流,按文檔上的說明,主要是用於對流執行的中間過程作debug的時候使用,由於Stream
使用的時候通常都是鏈式調用的,因此可能會執行屢次流操做,若是想看每一個元素在屢次流操做中間的流轉狀況,就可使用這個方法實現
Stream.of("one", "two", "three", "four") .filter(e -> e.length() > 3) .peek(e -> System.out.println("Filtered value: " + e)) .map(String::toUpperCase) .peek(e -> System.out.println("Mapped value: " + e)) .collect(Collectors.toList()); 輸出: Filtered value: three Mapped value: THREE Filtered value: four Mapped value: FOUR
limit
方法會對流進行順序截取,從第1個元素開始,保留最多maxSize
個元素
Stream<String> stringStream = Stream.of("-2", "-1", "0", "1", "2", "3"); //截取前3個元素,subStringStream -> ("-2", "-1", "0") Stream<String> subStringStream = stringStream.limit(3);
skip
方法用於跳過前n個元素,若是流中的元素數量不足n,則返回一個空的流
Stream<String> stringStream = Stream.of("-2", "-1", "0", "1", "2", "3"); //跳過前3個元素,subStringStream -> ("1", "2", "3") Stream<String> subStringStream = stringStream.skip(3);
forEach
方法的做用跟普通的for循環相似,不過這個能夠支持多線程遍歷,可是不保證遍歷的順序
Stream<String> stringStream = Stream.of("-2", "-1", "0", "1", "2", "3"); //單線程遍歷輸出元素 stringStream.forEach(System.out::println); //多線程遍歷輸出元素 stringStream.parallel().forEach(System.out::println);
forEachOrdered
方法能夠保證順序遍歷,好比這個流是從外部傳進來的,而後在這以前調用過parallel
方法開啓了多線程執行,就可使用這個方法保證單線程順序遍歷
Stream<String> stringStream = Stream.of("-2", "-1", "0", "1", "2", "3"); //順序遍歷輸出元素 stringStream.forEachOrdered(System.out::println); //多線程遍歷輸出元素,下面這行跟上面的執行結果是同樣的 //stringStream.parallel().forEachOrdered(System.out::println);
toArray
有一個無參和一個有參的方法,無參方法用於把流中的元素轉換成Object數組
Stream<String> stringStream = Stream.of("-2", "-1", "0", "1", "2", "3"); Object[] objArray = stringStream.toArray();
有參方法toArray(IntFunction<A[]> generator)
支持把流中的元素轉換成指定類型的元素數組
Stream<String> stringStream = Stream.of("-2", "-1", "0", "1", "2", "3"); String[] strArray = stringStream.toArray(String[]::new);
reduce
有三個重載方法,做用是對流內元素作累進操做
第一個reduce(BinaryOperator<T> accumulator)
accumulator
爲累進操做的具體計算
單線程等下以下代碼
boolean foundAny = false; T result = null; for (T element : this stream) { if (!foundAny) { foundAny = true; result = element; } else result = accumulator.apply(result, element); } return foundAny ? Optional.of(result) : Optional.empty();
Stream<Integer> numStream = Stream.of(-2, -1, 0, 1, 2, 3); //查找最小值 Optional<Integer> min = numStream.reduce(BinaryOperator.minBy(Integer::compareTo)); //輸出 -2 System.out.println(min.get()); //過濾出大於5的元素流 numStream = Stream.of(-2, -1, 0, 1, 2, 3).filter(num -> num > 5); //查找最小值 min = numStream.reduce(BinaryOperator.minBy(Integer::compareTo)); //輸出 Optional.empty System.out.println(min);
第二個reduce(T identity, BinaryOperator<T> accumulator)
identity
爲累進操做的初始值accumulator
同上
單線程等價以下代碼
T result = identity; for (T element : this stream) result = accumulator.apply(result, element) return result;
Stream<Integer> numStream = Stream.of(-2, -1, 0, 1, 2, 3); //累加計算全部元素的和,sum=3 int sum = numStream.reduce(0, Integer::sum);
第三個reduce(U identity, BiFunction<U, ? super T, U> accumulator, BinaryOperator<U> combiner)
identity
和accumulator
同上combiner
用於多線程執行的狀況下合併最終結果
Stream<Integer> numStream = Stream.of(-2, -1, 0, 1, 2, 3); int sum = numStream.parallel().reduce(0, (a, b) -> { System.out.println("accumulator執行:" + a + " + " + b); return a + b; }, (a, b) -> { System.out.println("combiner執行:" + a + " + " + b); return a + b; }); System.out.println("最終結果:"+sum); 輸出: accumulator執行:0 + -1 accumulator執行:0 + 1 accumulator執行:0 + 0 accumulator執行:0 + 2 accumulator執行:0 + -2 accumulator執行:0 + 3 combiner執行:2 + 3 combiner執行:-1 + 0 combiner執行:1 + 5 combiner執行:-2 + -1 combiner執行:-3 + 6 最終結果:3
collect
有兩個重載方法,主要做用是把流中的元素做爲集合轉換成其餘Collection
的子類,其內部實現相似於前面的累進操做
第一個collect(Supplier<R> supplier, BiConsumer<R, ? super T> accumulator, BiConsumer<R, R> combiner)
supplier
須要返回開始執行時的默認結果accumulator
用於累進計算用combiner
用於多線程合併結果
單線程執行等價於以下代碼
R result = supplier.get(); for (T element : this stream) accumulator.accept(result, element); return result;
第二個collect(Collector<? super T, A, R> collector)
collector
實際上是對上面的方法參數的一個封裝,內部執行邏輯是同樣的,只不過JDK提供了一些默認的Collector
實現
Stream<Integer> numStream = Stream.of(-2, -1, 0, 1, 2, 3); List<Integer> numList = numStream.collect(Collectors.toList()); Set<Integer> numSet = numStream.collect(Collectors.toSet());
min
方法用於計算流內元素的最小值
Stream<Integer> numStream = Stream.of(-2, -1, 0, 1, 2, 3); Optional<Integer> min = numStream.min(Integer::compareTo);
min
方法用於計算流內元素的最大值
Stream<Integer> numStream = Stream.of(-2, -1, 0, 1, 2, 3); Optional<Integer> max = numStream.max(Integer::compareTo);
count
方法用於統計流內元素的總個數
Stream<Integer> numStream = Stream.of(-2, -1, 0, 1, 2, 3); //count=6 long count = numStream.count();
anyMatch
方法用於匹配校驗流內元素是否有符合指定條件的元素
Stream<Integer> numStream = Stream.of(-2, -1, 0, 1, 2, 3); //判斷是否包含正數,hasPositiveNum=true boolean hasPositiveNum = numStream.anyMatch(num -> num > 0);
allMatch
方法用於匹配校驗流內元素是否全部元素都符合指定條件
Stream<Integer> numStream = Stream.of(-2, -1, 0, 1, 2, 3); //判斷是否所有是正數,allNumPositive=false boolean allNumPositive = numStream.allMatch(num -> num > 0);
noneMatch
方法用於匹配校驗流內元素是否都不符合指定條件
Stream<Integer> numStream = Stream.of(-2, -1, 0, 1, 2, 3); //判斷是否沒有小於0的元素,noNegativeNum=false boolean noNegativeNum = numStream.noneMatch(num -> num < 0);
findFirst
方法用於獲取第一個元素,若是流是空的,則返回Optional.empty
Stream<Integer> numStream = Stream.of(-2, -1, 0, 1, 2, 3); //獲取第一個元素,firstNum=-2 Optional<Integer> firstNum = numStream.findFirst();
findAny
方法用於獲取流中的任意一個元素,若是流是空的,則返回Optional.empty,由於可能會使用多線程,因此不保證每次返回的是同一個元素
Stream<Integer> numStream = Stream.of(-2, -1, 0, 1, 2, 3); Optional<Integer> anyNum = numStream.findAny();