簡體   English   中英

使用 Stream.sum() 多次使用 stream

[英]Consuming stream multiple times with Stream.sum()

stream 應該只運行一次(調用中間或終端 stream 操作)。

我明白了,但是為什么找到 stream 的總和不消耗它? 我可以運行下面的代碼,沒有任何例外。

double totalPrice = stream.mapToDouble(product -> product.price).sum();
List<Product> products = stream.map(this::convert).collect(Collectors.toList());

為什么sum不是終端運算符? 與將 stream 元素收集到列表中有何不同?

文檔

未指定 stream 是否可以使用一次或多次。 文檔說“應該操作......只操作一次”,而不是“必須”或“可以”。

取決於stream 的底層實現和來源。 因此,對於流來說,多次執行它的能力通常是未定義的。


實現

您可能能夠找到可以使用兩次或多次的 stream,特別是對於自定義實現或預防檢測可能過於昂貴而無法實現的實現。

但同樣,文檔不支持它。 它可能是當前的實現,但這可以隨時更改,在任何 Java 版本中。 它可能會拋出異常,可能會導致錯誤行為,但未指定。

這是一個小示例,它使用sum()引發異常,因為它具有這樣的檢測(JDK 11):

Stream<Integer> stream = List.of(1, 2, 3, 4).stream();

int first = stream
    .mapToInt(i -> i)
    .sum();

int second = stream
    .mapToInt(i -> i)
    .sum();

// throws IllegalStateException: stream has already been operated upon or closed

結論

正如文檔所暗示的,其意圖絕對是不要多次使用 stream 因此,即使某個實現可能是可行的,也要避免它


為什么?

你可能會問自己為什么Stream不支持多次迭代。 畢竟,像 ArrayList 這樣的ArrayList沒有任何問題,而且這似乎是一個常見的用例。

流的scope比 collections 大得多。 在典型集合上創建的 stream 可能很容易支持多次迭代。 但是 stream 與文件或網絡連接等資源相關聯,例如Files.lines(...)返回的 stream 不能。 這樣的功能對於文件來說將是非常耗費資源和昂貴的,甚至可能不支持其他功能,例如之后可能會關閉的 Web 連接。

更進一步,您可以輕松創建一個無限的 stream 生成隨機數:

Stream<Double> stream = Stream.generate(Math::random);

雖然它可以很容易地支持多種用途,但再次迭代時不可能再次生成相同的序列。

另一個例子,一個 stream 消耗資源而不恢復它們:

Queue<Integer> queue = ...
Stream<Integer> stream = Stream.generate(queue::poll);

這個 stream 將從隊列中刪除元素。 他們在 stream 使用后消失了。 stream 的另一個迭代將無法再接觸死物。

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM