ホームページ >Java >&#&チュートリアル >Java Streams で ` flatMap() ` の後に `filter()` が遅延していないように見えるのはなぜですか?

Java Streams で ` flatMap() ` の後に `filter()` が遅延していないように見えるのはなぜですか?

Susan Sarandon
Susan Sarandonオリジナル
2024-12-23 15:01:10872ブラウズ

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

Java ストリームの flatMap() の後、filter() が「完全に」Lazy ではないのはなぜですか?

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() の実装は、シンクが終了するまでスプリッテレータで tryAdvance() を継続的に呼び出します。キャンセルを要求するか、スプリッテレータが使い果たされます。 flatMap() の場合、filter() がすでに一致を見つけた場合でも、スプリッテレータは早期終了の可能性なしに続行します。

修正

この問題は Java 10 で解決され、Java 8 にバックポートされました。この実装では、次のような短絡操作が行われた場合に flatMap() で早期終了できるようになりました。

結論

当然のことながら、filter() が flatMap() の後で遅延していないかのように動作する理由は混乱を招く可能性があります。基礎となる Java Streams 実装によってこの動作が決定され、これは後に Java 10 で対処され、Java 8 にバックポートされました。このようなシナリオを効率的に処理するには、この理解が重要です。

以上がJava Streams で ` flatMap() ` の後に `filter()` が遅延していないように見えるのはなぜですか?の詳細内容です。詳細については、PHP 中国語 Web サイトの他の関連記事を参照してください。

声明:
この記事の内容はネチズンが自主的に寄稿したものであり、著作権は原著者に帰属します。このサイトは、それに相当する法的責任を負いません。盗作または侵害の疑いのあるコンテンツを見つけた場合は、admin@php.cn までご連絡ください。