首頁 > Java > java教程 > 為什麼 Java Streams 中的「filter()」在「flatMap()」之後顯得不那麼懶惰?

為什麼 Java Streams 中的「filter()」在「flatMap()」之後顯得不那麼懶惰?

Susan Sarandon
發布: 2024-12-23 15:01:10
原創
904 人瀏覽過

Why Does `filter()` Seem Non-Lazy After `flatMap()` in Java Streams?

為什麼在 Java Streams 中,filter() 在 flatMap() 之後不是「完全」惰性的?

在 Java 8 流中,中間操作如filter() 和 flatMap() 是惰性的,這表示它們在呼叫像 findFirst() 這樣的終端操作之前不會執行。然而,當 filter() 跟隨 flatMap() 時,這種惰性並沒有完全實現,從而導致意外的行為。

考慮這個程式碼範例:

Stream.of(1, 2, 3)
        .filter(i -> {
            System.out.println(i);
            return true;
        })
        .findFirst()
        .get();
登入後複製

輸出顯示只有第一個列印了元素,表示filter()是懶惰的,並且在滿足條件時短路。相較之下:

Stream.of(1, 2, 3)
        .flatMap(i -> Stream.of(i - 1, i, i + 1))
        .flatMap(i -> Stream.of(i - 1, i, i + 1))
        .filter(i -> {
            System.out.println(i);
            return true;
        })
        .findFirst()
        .get();
登入後複製

令人驚訝的是,所有元素都被印出來。即使 filter() 立即滿足其條件,它也會繼續處理流的後續元素。

原因

此行為是由於 Java Streams 實作造成的。在 flatMap() 之後,流不再包含原始元素。相反,它包含 flatMap() 產生的一系列扁平化元素。當filter()跟隨時,它對這些扁平化的元素進行操作,而不是原始流。

findFirst()中使用的forEachWithCancel()的實現,不斷地在spliterator上呼叫tryAdvance(),直到sink請求取消或 spliterator 已耗盡。在 flatMap() 的情況下,即使 filter() 已經找到匹配項,分割器也會繼續前進,而不會提前終止。

修正

這個問題已在 Java 10 中解決,並向後移植到 Java 8。現在,當像 filter() 這樣的短路操作被執行時,該實作允許在 flatMap() 中提前終止。

結論

可以理解的是,為什麼filter()在flatMap()之後表現得好像不是懶惰的,這可能會令人困惑。底層 Java Streams 實作規定了這種行為,後來在 Java 10 中解決了這個問題,並向後移植到 Java 8。這種理解對於有效處理此類場景至關重要。

以上是為什麼 Java Streams 中的「filter()」在「flatMap()」之後顯得不那麼懶惰?的詳細內容。更多資訊請關注PHP中文網其他相關文章!

來源:php.cn
本網站聲明
本文內容由網友自願投稿,版權歸原作者所有。本站不承擔相應的法律責任。如發現涉嫌抄襲或侵權的內容,請聯絡admin@php.cn
作者最新文章
熱門教學
更多>
最新下載
更多>
網站特效
網站源碼
網站素材
前端模板