所有流計算都有一種共同的結構:它們具有一個流來源、0 或多個中間操作,以及一個終止操作。
流的元素可以是對象引用 (Stream<String>
),也可以是原始整數 (IntStream
)、長整型 (LongStream
) 或雙精度 (DoubleStream
)。
JDK 中的流來源
方法 | 描述 |
---|---|
Collection.stream() |
使用一個集合的元素創建一個流。 |
Stream.of(T...) |
使用傳遞給工廠方法的參數創建一個流。 |
Stream.of(T[]) |
使用一個數組的元素創建一個流。 |
Stream.empty() |
創建一個空流。 |
Stream.iterate(T first, BinaryOperator<T> f) |
創建一個包含序列 first, f(first), f(f(first)), ... 的無限流 |
Stream.iterate(T first, Predicate<T> test, BinaryOperator<T> f) |
(僅限 Java 9)類似於 Stream.iterate(T first, BinaryOperator<T> f) ,但流在測試預期返回 false 的第一個元素上終止。 |
Stream.generate(Supplier<T> f) |
使用一個生成器函數創建一個無限流。 |
IntStream.range(lower, upper) |
創建一個由下限到上限(不含)之間的元素組成的 IntStream 。 |
IntStream.rangeClosed(lower, upper) |
創建一個由下限到上限(含)之間的元素組成的 IntStream 。 |
BufferedReader.lines() |
創建一個有來自 BufferedReader 的行組成的流。 |
BitSet.stream() |
創建一個由 BitSet 中的設置位的索引組成的 IntStream 。 |
Stream.chars() |
創建一個與 String 中的字符對應的 IntStream 。 |
中間操作負責將一個流轉換為另一個流,中間操作包括 filter()
(選擇與條件匹配的元素)、map()
(根據函數來轉換元素)、distinct()
(刪除重復)、limit()
(在特定大小處截斷流)和 sorted()
。
中間流操作
操作 | 內容 |
---|---|
filter(Predicate<T>) |
與預期匹配的流的元素 |
map(Function<T, U>) |
將提供的函數應用於流的元素的結果 |
flatMap(Function<T, Stream<U>> |
將提供的流處理函數應用於流元素后獲得的流元素 |
distinct() |
已刪除了重復的流元素 |
sorted() |
按自然順序排序的流元素 |
Sorted(Comparator<T>) |
按提供的比較符排序的流元素 |
limit(long) |
截斷至所提供長度的流元素 |
skip(long) |
丟棄了前 N 個元素的流元素 |
takeWhile(Predicate<T>) |
(僅限 Java 9)在第一個提供的預期不是 true 的元素處階段的流元素 |
dropWhile(Predicate<T>) |
(僅限 Java 9)丟棄了所提供的預期為 true 的初始元素分段的流元素 |
中間操作始終是惰性的:調用中間操作只會設置流管道的下一個階段,不會啟動任何操作。
重建操作可進一步划分為無狀態 和有狀態 操作。
無狀態操作(比如 filter()
或 map()
)可獨立處理每個元素,而有狀態操作(比如 sorted()
或 distinct()
)可合並以前看到的影響其他元素處理的元素狀態。
數據集的處理在執行終止操作時開始,比如縮減(sum()
或 max()
)、應用 (forEach()
) 或搜索 (findFirst()
) 操作。
終止操作會生成一個結果或副作用。
執行終止操作時,會終止流管道,如果您想再次遍歷同一個數據集,可以設置一個新的流管道。
終止流操作
操作 | 描述 |
---|---|
forEach(Consumer<T> action) |
將提供的操作應用於流的每個元素。 |
toArray() |
使用流的元素創建一個數組。 |
reduce(...) |
將流的元素聚合為一個匯總值。 |
collect(...) |
將流的元素聚合到一個匯總結果容器中。 |
min(Comparator<T>) |
通過比較符返回流的最小元素。 |
max(Comparator<T>) |
通過比較符返回流的最大元素。 |
count() |
返回流的大小。 |
{any,all,none}Match(Predicate<T>) |
返回流的任何/所有元素是否與提供的預期相匹配。 |
findFirst() |
返回流的第一個元素(如果有)。 |
findAny() |
返回流的任何元素(如果有)。 |
流與集合比較
盡管流在表面上可能類似於集合(您可以認為二者都包含數據),但事實上,它們完全不同。集合是一種數據結構;它的主要關注點是在內存中組織數據,而且集合會在一段時間內持久存在。集合通常可用作流管道的來源或目標,但流的關注點是計算,而不是數據。數據來自其他任何地方(集合、數組、生成器函數或 I/O 通道),而且可通過一個計算步驟管道處理來生成結果或副作用,在此刻,流已經完成了。流沒有為它們處理的元素提供存儲空間,而且流的生命周期更像一個時間點 — 調用終止操作。不同於集合,流也可以是無限的;相應地,一些操作(limit()
、findFirst()
)是短路,而且可在無限流上運行有限的計算。
集合和流在執行操作的方式上也不同。集合上的操作是急切和突變性的;在 List
上調用 remove()
方法時,調用返回后,您知道列表狀態會發生改變,以反映指定元素的刪除。對於流,只有終止操作是急切的;其他操作都是惰性的。流操作表示其輸入(也是流)上的功能轉換,而不是數據集上的突變性操作(過濾一個流會生成一個新流,新流的元素是輸入流的子集,但沒有從來源刪除任何元素)。