web-dev-qa-db-ja.com

Java 8ストリーム短絡

Java 8、について少し読んでみましたが、ストリームとその削減について少し説明し、いつ短絡が可能になるかについて説明する this ブログの投稿に行きました。下部にそれは述べています:

findFirstまたはfindAnyの場合、述語に一致する最初の値のみが必要であることに注意してください(ただし、findAnyが最初の値を返すことは保証されていません)。ただし、ストリームに順序がない場合、findFirstfindAnyのように動作することが期待されます。演算子がallMatchnoneMatchかどうかを判断するためにすべての値を評価する場合があるため、anyMatchtruefalseの操作はストリームをまったく短絡しない場合があります。したがって、これらを使用する無限ストリームは終了しない場合があります。

findFirstまたはfindAnyが還元を短絡する可能性があることがわかりました。なぜなら、要素を見つけたらすぐに、それ以上処理する必要がないからです。

しかし、allMatchnoneMatchanyMatchでこれが不可能なのはなぜですか? allMatchの場合、述語と一致しないものが見つかった場合、処理を停止できます。どれも同じです。そして、anyMatchは、findAnyとほとんど同じであるため、特に私には意味がありません(返されるものを除いて)?

これらの3つは、すべての値を評価する必要があるため、短絡しない可能性があると言っても、findFirst/Any

私が見逃している根本的な違いはありますか?私は何が起こっているのか本当に理解していませんか?

22
Koekje

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()を使用して)、基礎となるストリーム要素が無限にあることを確認する必要があるため、この操作は完了しません。私もそのようなストリームを無限と呼びます。ただし、このようなストリームを使用すると、anyMatchfindAnyの両方が終了することはありません。

_Stream.generate(() -> 1).filter(x -> x < 0).anyMatch(x -> true);
Stream.generate(() -> 1).filter(x -> x < 0).findAny();
_

したがって、findAny()の終了も保証されていません。これは、前の中間ストリーム操作に依存します。

結論として、そのブログ投稿は非常に誤解を招くものだと評価します。私の意見では、無限ストリームの動作は公式 JavaDoc でよりよく説明されています。

20
Tagir Valeev

回答が更新されました

「findFirstまたはfindAnyには、述語に一致する最初の値のみが必要である」と書かれている場合、ブログの投稿は間違っていると思います。

Javadocの allMatch(Predicate)anyMatch(Predicate)noneMatch(Predicate)findAny() の場合、および findFirst()

これは短絡端子操作です。

ただし、findFirstおよびfindAnyにはPredicateがないことに注意してください。したがって、最初の値/任意の値を見ると、どちらもすぐに戻ることができます。他の3つは条件付きで、条件が発生しない場合は永久にループする可能性があります。

8
Andreas

Oracleのストリームドキュメントによると: https://docs.Oracle.com/javase/8/docs/api/Java/util/stream/package-summary.html#StreamOps

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

5つの関数すべてに次の行があります。

これは短絡端子操作です。

関数の説明。

3
WillShackleford

Javadocが「短絡していない可能性があります」と言っている場合、それは短絡操作ではないことを示しているだけであり、値によっては、ストリーム全体が処理される場合があります。

一方、findFirstfindAnyは、残りのストリームを処理する必要がないため、短絡することが保証されています。

1
Trevor Freeman

anyMatch、noneMatchおよびallMatchはブール値を返すため、ロジックを証明するためにすべてをチェックする必要がある場合があります。

findFirstとfindAnyは、できるかぎり最初に見つけ、それを返すことを気にします。

編集:特定のデータセットでは、Matchメソッドは常に同じ値を返すことが保証されていますが、Findメソッドはそうではありません。順序が異なり、返される値に影響する可能性があるためです。

説明されている短絡は、特定のデータセットの一貫性に欠けているFindメソッドについて話しています。

0
Jaeger Kor