Java 8ストリームAPIでpeek()とallMatch()が連動する仕組み


10

以下のようなpeekメソッドのJava 8 Stream APIに関するクイズを見つけました

Arrays.asList("Fred", "Jim", "Sheila")
      .stream()
      .peek(System.out::println)
      .allMatch(s -> s.startsWith("F"));

出力は

Fred
Jim

このストリームがどのように機能するのか混乱していますか?私の期待される結果は

Fred
Jim
Sheila

peek()メソッドは中間操作であり、Streamの各要素を処理します。誰かがこれを説明できますか?

回答:


10

これは、ショートサーキットと呼ばれるストリームの最適化です。基本的に、最終的な結果がわかっている場合は実行する意味がないため、ストリームallMatchで不要な中間操作が実行されないようになります。

これが起こったようです:

take"Fred"
peek("Fred")
evaluate("Fred".startsWith("F"))
decide whether the result of allMatch() is known for sure: Not yet

take"Jim"
peek("Jim")
evaluate("Jim".startsWith("F"))
decide whether the result of allMatch() is known for sure: Yes

ときに"Jim".startsWith("F")評価され、結果がallMatch(s -> s.startsWith("F"))特定のために知られています。後"Jim"にパイプラインに入る値は関係ありません。「F」で始まるすべての値はfalseであることがわかります

これはpeek/のallMatch組み合わせに固有のものではなく、複数の中間および端子短絡操作があります。java.util.streamパッケージのドキュメントの状態:

さらに、一部の操作は短絡操作と見なされます。中間演算は、無限の入力が提示されたときに結果として有限のストリームが生成される可能性がある場合、短絡です。端末操作は、無限の入力が提示されたときに有限の時間で終了する可能性がある場合、短絡です。パイプラインで短絡操作を行うことは、無限ストリームの処理が有限時間で正常に終了するために必要ですが、十分ではありません。

例のように、これを有限ストリームに拡張し、操作を短絡することで、不要なパイプラインステップの実行を回避できます。


5
Arrays.asList("Fred", "Jim", "Sheila")
      .stream()
      .peek(System.out::println)
      .allMatch(s -> s.startsWith("F"));
  • はじめて、 Fred印刷されます。それに合う
  • 2回目Jimは、印刷されます。「すべてが一致しなかった」ため、allMatchは終了します。
  • したがって、最後のアイテムはストリームから消費されませんでした。

3

メソッドのドキュメントpeek言う(私の強調):

このストリームの要素で構成されるストリームを返します。要素が結果のストリームから消費されるときに、各要素に対して指定されたアクションを追加で実行します

したがって、この場合には、peek見ていない"Sheila"、その値は、ストリームから消費されていないため。"Jim"が消費されるとすぐに、の結果はであること.allMatch(s -> s.startsWith("F"))が既にわかっているfalseため、ストリームから要素をさらに消費する必要はありません。


1

allMatch()のJavaドキュメントによると:

このストリームのすべての要素が指定された述語と一致するかどうかを返します。結果の決定に必要でない場合、すべての要素の述語を評価しない場合があります。ストリームが空の場合、{@ code true}が返され、述語は評価されません。

@apiNote

このメソッドは、ストリームの要素に対する述語の普遍的な数量化を評価します(すべてのx P(x)に対して)。ストリームが空の場合、数量化は空虚に満たされていると言われ、常に{@code true}になります(P(x)に関係なく)。

ストリームのすべての要素が提供された述語と一致するか、ストリームが空の場合、このストリームの要素に適用する述語@return {@code true}、それ以外の場合は{@code false}

あなたの場合:

1-

p(x) : s -> s.startsWith("F")

X : "Fred"

result : X P(X) = true

2-

p(x) : s -> s.startsWith("F")

X : "Jim"

result : X P(X) = false

XP(X)= falseであるため、これ以上の評価は行われません。

boolean result = Arrays.asList("Fred", "Finda", "Fish")
            .stream()
            .peek(System.out::println)
            .allMatch(s -> s.startsWith("F"));
    System.out.println("Result "+result);

出力は:

Fred
Finda
Fish
Result true

ここでは、各要素からxP(x)= trueであるため、ストリームは完全に処理されました

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