流是Java API的新成員,它容許以聲明性方式處理數據集合(經過查詢語句來表達,而不是臨時編寫一個實現)。就如今來講,能夠把它們當作遍歷數據集的高級迭代器。此外,流還能夠透明地並行處理,無需寫任何多線程代碼了! java
流的使用通常包括三件事:數組
•一個數據源(如集合)來執行一個查詢;緩存
•一箇中間操做鏈,造成一條流的流水線;多線程
•一個終端操做,執行流水線,並能生成結果。 ide
流方法函數 |
含義ui |
示例this |
filterspa |
(中間操做)該操做會接受一個謂詞(一個返回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實戰