Collection.stream()。filter()。forEach()は、各ループの標準と比較して非効率ですか?


15

IntelliJ IDEAは、次のfor-eachループをJava 8の "forEach"呼び出しに置き換えるために、今私に勧めました:

    for (Object o : objects) {
        if (o instanceof SomeObject) {
            doSomething();
        }
    }

推奨される呼び出しは次のようになります。

objects.stream().filter(o -> o instanceof SomeObject).forEach(o -> doSomething());

Streamの基本的な機能がどのように機能するかを誤解していない限り、streamの使用は標準のfor-eachループのO(n)操作ではなくO(2n)操作であるように思われます。


8
なぜO ^ 2だと思いますか?実際、(a)より良い構文を可能にし、(b)余分なオーバーヘッドを導入しないために、ストリームは特に発明されました。(実際、遅延評価によってオーバーヘッドを削減することがよくあります。)
Kilian Foth

構文に基づいて、最初にフィルター処理を繰り返してから、フィルター処理されたオブジェクトをもう一度繰り返してコードを実行しているように見えます。
ミラナ

6
それを行ったとしても、O(2 * N)、つまりO(N)、つまり線形であり、2次ではありません。しかし、実際には反復は互いにインターリーブされてお​​り、結果がすでにわかっている場合は両方が早期に終了する可能性があります-それがストリームの美しさです。Java 8のストリームを読むのに15分を費やす価値は間違いありません。Venkat Subramaniamが書いているように、「ラムダ式はJava 8へのゲートウェイドラッグですが、ストリームは真の依存症です。」
Kilian Foth

1
その上:あなたのループはアンチパターンです;)
トーマスジャンク

1
@ThomasJunkそれがアンチパターンである方法を説明できますか?私はこれに慣れていません。
ミラナ

回答:


21

Javaストリームは、構文が示唆していることにもかかわらず、ステートメントごとにコレクションを1回反復しません。チェーン全体を各要素に、一度に1要素ずつ適用します。

あなたの場合、ストリームはループとまったく同じように動作します。要素を取り、それを述部と照合してから、操作を適用してから、次の要素に進みます。

弊社のサイトを使用することにより、あなたは弊社のクッキーポリシーおよびプライバシーポリシーを読み、理解したものとみなされます。
Licensed under cc by-sa 3.0 with attribution required.