https://www.runoob.com/java/java8-streams.html
https://www.cnblogs.com/baobeiqi-e/p/10096929.html
流是Java API的新成員,它允許以聲明性方式處理數據集合(通過查詢語句來表達,而不是臨時編寫一個實現)。就現在來說,可以把它們看成遍歷數據集的高級迭代器。此外,流還可以透明地並行處理,無需寫任何多線程代碼了!
流的使用一般包括三件事:
•一個數據源(如集合)來執行一個查詢;
•一個中間操作鏈,形成一條流的流水線;
•一個終端操作,執行流水線,並能生成結果。
流方法 |
含義 |
示例 |
filter |
(中間操作)該操作會接受一個謂詞(一個返回boolean的函數)作為參數,並返回一個包括所有符合謂詞的元素的流。 |
List<Dish> vegetarianMenu = menu.stream() .filter(Dish::isVegetarian) .collect(toList()); System.out.println(vegetarianMenu); |
distinct |
(中間操作)返回一個元素各異(根據流所生成元素的hashCode和equals方法實現)的流。 |
List<Integer> numbers = Arrays.asList(1, 2, 1, 3, 3, 2, 4); numbers.stream() .filter(i -> i % 2 == 0) .distinct() .forEach(System.out::println); |
limit |
(中間操作)會返回一個不超過給定長度的流。 |
List<Dish> dishes = menu.stream() .filter(d -> d.getCalories() > 300) .limit(3) .collect(toList()); System.out.println(dishes); |
skip |
(中間操作)返回一個扔掉了前n個元素的流。 |
List<Dish> dishes = menu.stream() .filter(d -> d.getCalories() > 300) .skip(2) .collect(toList()); System.out.println(dishes); |
map |
(中間操作)接受一個函數作為參數。這個函數會被應用到每個元素上,並將其映射成一個新的元素(使用映射一詞,是因為它和轉換類似,但其中的細微差別在於它是“創建一個新版本”而不是去“修改”)。 |
List<String> dishNames = menu.stream() .map(Dish::getName) .collect(toList()); System.out.println(dishNames); |
flatMap |
(中間操作)使用flatMap方法的效果是,各個數組並不是分別映射成一個流,而是映射成流的內容。所有使用map(Arrays::stream)時生成的單個流都被合並起來,即扁平化為一個流。 |
List<String> words = Arrays.asList("Goodbye", "World"); List<String> uniqueCharacters = words.stream() .map(w -> w.split("")) .flatMap(Arrays::stream) .distinct() .collect(Collectors.toList()); System.out.println(uniqueCharacters); |
sorted |
(中間操作)返回排序后的流 |
List<String> traderStr = menu.stream() .map(transaction -> transaction.getName()) .sorted() .collect(toList()); System.out.println(traderStr); |
anyMatch |
(終端操作)可以回答“流中是否有一個元素能匹配給定的謂詞”。 |
if (menu.stream().anyMatch(Dish::isVegetarian)) { System.out.println("The menu is (somewhat) vegetarian friendly!!"); } |
allMatch |
(終端操作)會看看流中的元素是否都能匹配給定的謂詞。 |
boolean isHealthy = menu.stream() .allMatch(d -> d.getCalories() < 1000); System.out.println(isHealthy); |
noneMatch |
(終端操作)可以確保流中沒有任何元素與給定的謂詞匹配。 |
boolean isHealthy = menu.stream() .noneMatch(d -> d.getCalories() >= 1000); System.out.println(isHealthy); |
findAny |
(終端操作)將返回當前流中的任意元素。 |
Optional<Dish> dish = menu.stream() .filter(Dish::isVegetarian) .findAny(); System.out.println(dish); |
findFirst |
(終端操作)有些流有一個出現順序(encounter order)來指定流中項目出現的邏輯順序(比如由List或排序好的數據列生成的流)。對於這種流,可能想要找到第一個元素。 |
List<Integer> someNumbers = Arrays.asList(1, 2, 3, 4, 5); Optional<Integer> firstSquareDivisibleByThree = someNumbers.stream() .map(x -> x * x) .filter(x -> x % 3 == 0) .findFirst(); System.out.println(firstSquareDivisibleByThree); |
forEach |
(終端操作)遍歷流 |
List<Integer> numbers = Arrays.asList(1, 2, 1, 3, 3, 2, 4); numbers.stream() .filter(i -> i % 2 == 0) .distinct() .forEach(System.out::println); |
collect |
(終端操作)收集器 |
List<String> traderStr = menu.stream() .map(transaction -> transaction.getName()) .sorted() .collect(toList()); |
reduce |
(終端操作)歸約reduce接受兩個參數: •一個初始值,這里是0; •一個BinaryOperator<T>來將兩個元素結合起來產生一個新值,這里我們用的是lambda (a, b) -> a + b。 |
List<Integer> numbers = Arrays.asList(1, 2, 1, 3, 3, 2, 4); int sum = numbers.stream().reduce(0, (a, b) -> a + b); System.out.println(sum); |
count |
(終端操作)返回此流中元素的計數。 |
long evenNumbers = IntStream.rangeClosed(1, 100) .filter(n -> n % 2 == 0) .count(); System.out.println(evenNumbers); |
•可以使用filter、distinct、skip和limit對流做篩選和切片。
•可以使用map和flatMap提取或轉換流中的元素。
•可以使用findFirst和findAny方法查找流中的元素。可以用allMatch、noneMatch和anyMatch方法讓流匹配給定的謂詞。
•這些方法都利用了短路:找到結果就立即停止計算;沒有必要處理整個流。
•可以利用reduce方法將流中所有的元素迭代合並成一個結果,例如求和或查找最大元素。
•filter和map等操作是無狀態的,它們並不存儲任何狀態。reduce等操作要存儲狀態才能計算出一個值。sorted和distinct等操作也要存儲狀態,因為它們需要把流中的所有元素緩存起來才能返回一個新的流。這種操作稱為有狀態操作。
•流有三種基本的原始類型特化:IntStream、DoubleStream和LongStream。它們的操作也有相應的特化。
•流不僅可以從集合創建,也可從值、數組、文件以及iterate與generate等特定方法創建。
•無限流是沒有固定大小的流。
附:示例中用到的類
package lambdasinaction.chap4; import java.util.*; public class Dish { private final String name; private final boolean vegetarian; private final int calories; private final Type type; public Dish(String name, boolean vegetarian, int calories, Type type) { this.name = name; this.vegetarian = vegetarian; this.calories = calories; this.type = type; } public String getName() { return name; } public boolean isVegetarian() { return vegetarian; } public int getCalories() { return calories; } public Type getType() { return type; } public enum Type { MEAT, FISH, OTHER } @Override public String toString() { return name; } public static final List<Dish> menu = Arrays.asList( new Dish("pork", false, 800, Dish.Type.MEAT), new Dish("beef", false, 700, Dish.Type.MEAT), new Dish("chicken", false, 400, Dish.Type.MEAT), new Dish("french fries", true, 530, Dish.Type.OTHER), new Dish("rice", true, 350, Dish.Type.OTHER), new Dish("season fruit", true, 120, Dish.Type.OTHER), new Dish("pizza", true, 550, Dish.Type.OTHER), new Dish("prawns", false, 400, Dish.Type.FISH), new Dish("salmon", false, 450, Dish.Type.FISH)); }
參考:java8實戰