消耗流
一個 Stream
當存在將僅被遍歷終端操作,像 count()
, collect()
或 forEach()
。否則,將不會對 Stream
執行任何操作。
在下面的示例中,沒有向 Stream
新增終端操作,因此不會呼叫 filter()
操作,也不會產生輸出,因為 peek()
不是終端操作。
IntStream.range(1, 10).filter(a -> a % 2 == 0).peek(System.out::println);
這是具有有效終端操作的 Stream
序列,因此產生輸出。
你也可以使用 forEach
而不是 peek
:
IntStream.range(1, 10).filter(a -> a % 2 == 0).forEach(System.out::println);
輸出:
2
4
6
8
在執行終端操作之後,Stream
被消耗並且不能被重用。
雖然給定的流物件無法重用,但很容易建立一個可重用的 Iterable
,它委託給一個流管道。這對於返回實時資料集的修改檢視而不必將結果收集到臨時結構中非常有用。
List<String> list = Arrays.asList("FOO", "BAR");
Iterable<String> iterable = () -> list.stream().map(String::toLowerCase).iterator();
for (String str : iterable) {
System.out.println(str);
}
for (String str : iterable) {
System.out.println(str);
}
輸出:
foo
bar
foo
bar
這是因為 Iterable
宣告瞭一個抽象方法 Iterator<T> iterator()
。這使它成為一個功能介面,由 lambda 實現,在每次呼叫時建立一個新流。
通常,Stream
的執行方式如下圖所示:
https://i.stack.imgur.com/lrwjM.jpg
注意 :即使沒有終端操作,也始終執行引數檢查 :
try {
IntStream.range(1, 10).filter(null);
} catch (NullPointerException e) {
System.out.println("We got a NullPointerException as null was passed as an argument to filter()");
}
輸出:
我們得到一個 NullPointerException,因為 null 作為引數傳遞給
filter()