Java 8、について少し読んでみましたが、ストリームとその削減について少し説明し、いつ短絡が可能になるかについて説明する this ブログの投稿に行きました。下部にそれは述べています:
findFirst
またはfindAny
の場合、述語に一致する最初の値のみが必要であることに注意してください(ただし、findAny
が最初の値を返すことは保証されていません)。ただし、ストリームに順序がない場合、findFirst
はfindAny
のように動作することが期待されます。演算子がallMatch
かnoneMatch
かどうかを判断するためにすべての値を評価する場合があるため、anyMatch
、true
、false
の操作はストリームをまったく短絡しない場合があります。したがって、これらを使用する無限ストリームは終了しない場合があります。
findFirst
またはfindAny
が還元を短絡する可能性があることがわかりました。なぜなら、要素を見つけたらすぐに、それ以上処理する必要がないからです。
しかし、allMatch
、noneMatch
、anyMatch
でこれが不可能なのはなぜですか? allMatch
の場合、述語と一致しないものが見つかった場合、処理を停止できます。どれも同じです。そして、anyMatch
は、findAny
とほとんど同じであるため、特に私には意味がありません(返されるものを除いて)?
これらの3つは、すべての値を評価する必要があるため、短絡しない可能性があると言っても、findFirst/Any
。
私が見逃している根本的な違いはありますか?私は何が起こっているのか本当に理解していませんか?
anyMatch
ファミリは述語を使用しますが、findAny
ファミリは使用しないため、微妙な違いがあります。技術的にはfindAny()
はanyMatch(x -> true)
のように見え、anyMatch(pred)
はfilter(pred).findAny()
のように見えます。ここに別の問題があります。単純な無限ストリームがあるとしましょう:
_Stream<Integer> s = Stream.generate(() -> 1);
_
したがって、そのようなストリームにfindAny()
を適用すると、常に短絡して終了しますが、anyMatch(pred)
の適用は述語に依存します。ただし、無限ストリームをフィルター処理してみましょう。
_Stream<Integer> s = Stream.generate(() -> 1).filter(x -> x < 0);
_
結果のストリームも無限ですか?それはトリッキーな質問です。実際には要素は含まれていませんが、これを判別するには(たとえば、.iterator().hasNext()
を使用して)、基礎となるストリーム要素が無限にあることを確認する必要があるため、この操作は完了しません。私もそのようなストリームを無限と呼びます。ただし、このようなストリームを使用すると、anyMatch
とfindAny
の両方が終了することはありません。
_Stream.generate(() -> 1).filter(x -> x < 0).anyMatch(x -> true);
Stream.generate(() -> 1).filter(x -> x < 0).findAny();
_
したがって、findAny()
の終了も保証されていません。これは、前の中間ストリーム操作に依存します。
結論として、そのブログ投稿は非常に誤解を招くものだと評価します。私の意見では、無限ストリームの動作は公式 JavaDoc でよりよく説明されています。
回答が更新されました
「findFirstまたはfindAnyには、述語に一致する最初の値のみが必要である」と書かれている場合、ブログの投稿は間違っていると思います。
Javadocの allMatch(Predicate) 、 anyMatch(Predicate) 、 noneMatch(Predicate) 、 findAny() の場合、および findFirst() :
これは短絡端子操作です。
ただし、findFirst
およびfindAny
にはPredicate
がないことに注意してください。したがって、最初の値/任意の値を見ると、どちらもすぐに戻ることができます。他の3つは条件付きで、条件が発生しない場合は永久にループする可能性があります。
Oracleのストリームドキュメントによると: https://docs.Oracle.com/javase/8/docs/api/Java/util/stream/package-summary.html#StreamOps
端末操作は、無限の入力が提示されたときに有限の時間で終了する可能性がある場合、短絡です。パイプラインで短絡操作を行うことは、無限ストリームの処理が有限時間で正常に終了するために必要ですが、十分ではありません。
5つの関数すべてに次の行があります。
これは短絡端子操作です。
関数の説明。
Javadocが「短絡していない可能性があります」と言っている場合、それは短絡操作ではないことを示しているだけであり、値によっては、ストリーム全体が処理される場合があります。
一方、findFirst
とfindAny
は、残りのストリームを処理する必要がないため、短絡することが保証されています。
anyMatch、noneMatchおよびallMatchはブール値を返すため、ロジックを証明するためにすべてをチェックする必要がある場合があります。
findFirstとfindAnyは、できるかぎり最初に見つけ、それを返すことを気にします。
編集:特定のデータセットでは、Matchメソッドは常に同じ値を返すことが保証されていますが、Findメソッドはそうではありません。順序が異なり、返される値に影響する可能性があるためです。
説明されている短絡は、特定のデータセットの一貫性に欠けているFindメソッドについて話しています。