三. 使用流java
流的使用通常包括三件事:數組
-- 一個數據源(如集合)來執行一個查詢;ide
-- 一箇中間操做鏈,造成一條流的流水線;函數
-- 一個終端操做,執行流水線,並能生成結果。spa
1.流操做:對象
篩選、切片、映射、查找、匹配、概括。(快速完成複雜數據查詢)排序
2.狀態接口
無狀態操做:從輸入流中獲得0或1個結果。他們沒有內部狀態。如map、filter。ip
有狀態操做:先接受一個流再生成一個流時,須要知道先前的歷史。get
3.Optional<T>類(java.util.Optional)是一個容器類,表明一個值存在或不存在。
Optional裏能夠迫使你顯式地檢查值是否存在或處理值不存在的情形的方法:
-- isPresent()將在Optional包含值的時候返回true,不然返回false;
-- ifPresent(Consumer<T> block)會在值存在的時候執行給定的代碼塊;
-- T get()會在值存在時返回值,不然拋出一個NoSuchElement異常;
-- T orElse(T other)會在值存在時返回值,不然返回一個默認值。
操做 | 描述 | 操做 | 類型 | 返回類型 | 使用的類型/函數式接口 | 函數描述符 | 說明 |
篩選 |
謂詞篩選 | filter | 中間 | Stream<T> | Predicate<T> | T -> boolean | |
篩選各異元素 | distinct() | 中間(有狀態-×××) | Stream<T> | 確保沒有重複 | |||
切片 |
截短流 | limit(n) | 中間(有狀態-有界) | Stream<T> | long | ||
跳過元素 | skip(n) | 中間(有狀態-有界) | Stream<T> | long | skip(n)與limit(n)互補 | ||
映射 |
對流中每個元素應用函數 | map | 中間 | Stream<R> | Function<T, R> | T -> R | 接受一個函數做爲參數 |
流的扁平化:各個數組並非分別映射成一個流,而是映射成留的內容 | flatMap(Arrays::stream) | 中間 | Stream<R> | Function<T, Stream<R>> | T -> Stream<R> | 將[h,e,l,l,o],[w,o,r,l,d]變成[h,e,l,l,o,w,o,r,l,d] | |
排序 | sorted | 中間(有狀態-×××) | Stream<T> | Comparator<T> | (T, T) -> int | ||
查找 |
返回當前流中的任意元素 | findAny | 終端 | Optional<T> | //若是包含一個值就返回它,不然什麼都不作 menu.stream().filter(Dish::isvegetarian).findAny().ifPresent(d -> System.out.println(d.getName)); |
||
查找第一個元素 | findFirst | 終端 | Optional<T> | ||||
匹配 |
檢查謂詞是否匹配至少一個元素 | anyMatch | 終端 | boolean | Predicate<T> | T -> boolean | if(menu.stream().anyMatch(Dish::isVegetarian)) { System.out.println("The menu is (somewhat) vegetarian friendly!!"); } |
檢查謂詞是否匹配全部元素 | allMatch | 終端 | boolean | Predicate<T> | T -> boolean | boolean isHealthy = menu.stream().allMatch(d -> d.getCalories() < 1000); | |
沒有任何元素與給定的謂詞匹配 | noneMatch | 終端 | boolean | Predicate<T> | T -> boolean | boolean isHealthy = menu.stream().noneMatch(d -> d.getCalories() >= 1000); | |
歸約 |
對流中的數字求和 | reduce | 終端(有狀態,有界) | Optional<T> | BinaryOperator<T> | (T, T) -> T | //有初始值 int sum = numbers.stream().reduce(0, Integer :: sum); //無初始值,返回Optional是考慮流中沒有任何元素的狀況,reduce元素沒法返回其和 Optional<Integer> sum = numbers.stream().reduce((a, b) -> a * b); |
最大值 | reduce(Integer::max) | 終端(有狀態,有界) | Optional<T> | Optional<Integer> max = numbers.stream().reduce(Integer::max); | |||
最小值 | reduce(Integer::min) | 終端(有狀態,有界) | Optional<T> | Optional<Integer> min = numbers.stream().reduce(Integer::min); | |||
collect | 終端 | R | Collector<T, A, R> | T -> void | |||
forEach | 終端 | void | Consumer<T> | ||||
計算流中元素個數 | count | 終端 | long | long count = menu.stream().count(); |
eg:
public void testList() { List<Integer> list1 = Arrays.asList(1,2,3); List<Integer> list2 = Arrays.asList(3,4); //給定列表[1,2,3],[3,4]返回[(1,3),(1,4),(2,3),(2,4),(3,3),(3,4)] List<int[]> result = list1.stream() .flatMap(i -> list2.stream().map(j -> new int[]{i, j}) ).collect(Collectors.toList()); //給定列表[1,2,3],[3,4]返回總和能被3整除的數對:(2,4)和(3,3) List<int[]> result1 = list1.stream() .flatMap(i -> list2.stream().filter(j -> (i + j) % 3 == 0) .map(j -> new int[]{i, j}) ) .collect(Collectors.toList()); }
4.特殊的流
數值流
原始類型流特化:特化是爲了不裝箱形成的複雜性(相似int和Integer之間的效率差別)。
原始類型特化流接口 | 映射到數值流 | 將數值流轉換回對象流 | Optional原始類型特化 |
IntStream | mapToInt | boxed() | OptionalInt |
DoubleStream | mapToDouble | boxed() | OptionalDouble |
LongStream | mapToLong | boxed() | OptionalLong |
數值範圍:IntStream和LongStream有靜態方法幫助生成這種範圍:range(接受起始值)和rangeClosed(接受結束值)。
5.構建流
建立流的方法 | 說明 | 舉例 |
Stream.of | 經過顯式值建立流 | Stream.of("hello", "world") |
Stream.empty | 獲得空流 | Stream.empty() |
Arrays.stream | 由數組建立流 | int[] numbers = {2,3,4,5}; int sum = Arrays.stream(numbers).sum(); |
Files.lines | 由文件生成流,其中每一個元素都是給定文件中的一行 | long uniqueWords = 0; try(Stream<String> lines = Files.lines(Paths.get("data.txt"), Charset.defaultCharset())){ uniqueWords = lines.flatMap(line -> Arrays.stream(line.split(" "))) //生成單詞流 .distinct().count;//刪除重複項並得出共有多少各不相同的單詞 } catch(IOException e) {} |
Stream.iterate | 由函數生成流:建立無限流,使用limit()方法限制流的大小 | //依次對每一個新生成的值應用函數 Stream.iterate(0, n -> n + 2).limit(10).forEach(System.out::println); |
Stream.generate | //接受一個Supplier<T>類型的Lambda提供新的值 IntStream tows = IntStream.generate(new IntSupplier() { public int getAsInt() { return 2; } }); |