Java8のAPIStream#findAny()
とStream#findFirst()
の間で少し混乱してい Stream
ます。
私が理解したのは、たとえば、フィルターと組み合わせて使用した場合、両方がストリームから最初に一致した要素を返すということです。
では、なぜ同じタスクに2つの方法があるのでしょうか。私は何かが足りないのですか?
Java8のAPIStream#findAny()
とStream#findFirst()
の間で少し混乱してい Stream
ます。
私が理解したのは、たとえば、フィルターと組み合わせて使用した場合、両方がストリームから最初に一致した要素を返すということです。
では、なぜ同じタスクに2つの方法があるのでしょうか。私は何かが足りないのですか?
回答:
私が理解したのは、たとえば、フィルターと組み合わせて使用した場合、両方がストリームから最初に一致した要素を返すということです。
それは真実ではない。javadocによると、Stream#findAny()
:
ストリームの一部の要素を
Optional<T>
説明するものを返しますOptional<T>
。ストリームが空の場合は空を返します。この操作の動作は明らかに非決定的です。ストリーム内の任意の要素を自由に選択できます。これは、並列操作で最大のパフォーマンスを実現するためです。
whileStream.findFirst()
は、ストリームの最初の要素Optional<T>
を厳密に記述したものを返します。Stream
クラスが持っていない.findOne()
私はあなたが意味するものと仮定して、方法を.findFirst()
。
findAny
、特に並列ストリーム操作では、ランダムな(一種の)要素から任意の要素を返すことができます
いいえ、どちらもストリームの最初の要素を返しません。
からStream.findAny()
(強調鉱山):
ストリームの一部の要素を
Optional
説明するものを返しますOptional
。ストリームが空の場合は空を返します。これは短絡端子操作です。
この操作の動作は明らかに非決定的です。ストリーム内の任意の要素を自由に選択できます。これは、並列操作で最大のパフォーマンスを実現するためです。コストは、同じソースで複数の呼び出しが同じ結果を返さない可能性があることです。(安定した結果が必要な場合は、
findFirst()
代わりに使用してください。)
つまり、簡単に言うと、ストリームの最初の要素を選択する場合と選択しない場合があります。
現在のOracle固有の実装では、非並列パイプラインの最初の要素が返されると思います。ただし、並列パイプラインでは、常にそうなるとは限りません(たとえばSystem.out.println(IntStream.range(0, 100).parallel().findAny());
、実行すると返されOptionalInt[50]
ます)。とにかく、あなたはそれに頼ってはいけません。
findFirstはストリームの最初の要素を返しますが、findAnyはストリーム内の任意の要素を自由に選択できます。
List<String> lst1 = Arrays.asList("Jhonny", "David", "Jack", "Duke", "Jill","Dany","Julia","Jenish","Divya");
List<String> lst2 = Arrays.asList("Jhonny", "David", "Jack", "Duke", "Jill","Dany","Julia","Jenish","Divya");
Optional<String> findFirst = lst1.parallelStream().filter(s -> s.startsWith("D")).findFirst();
Optional<String> fidnAny = lst2.parallelStream().filter(s -> s.startsWith("J")).findAny();
System.out.println(findFirst.get()); //Always print David
System.out.println(fidnAny.get()); //Print Jack/Jill/Julia :behavior of this operation is explicitly nondeterministic
並列モードでは、findAny
順序は保証されませんが、保証されfindFirst
ます。
違いを示すためにコードスニペットを作成しました。アクセスしてください
私はただの気をつけろと言うだろうfindFirst()
とfindAny()
使用している間。
Javadoc(こことここ)からのように、両方のメソッドはストリームから任意の要素を返します–ストリームに遭遇順序がない限り、この場合findFirst()
、最初の要素を返し、findAny()
任意の要素を返します。
list
ISBNとBOOK名で構成されるカスタムがあるとします。シナリオについては、次の例を見てください。
public class Solution {
private Integer ISBN;
private String BookName;
public Solution(int i, String string) {
ISBN =i;
BookName = string;
}
//getters and setters
}
public static void main(String[] args) {
List<Solution> Library = Arrays.asList(new Solution(12,"Java in Action"),new Solution(13,"Java 8"),new Solution(15,"Java 8 Features"),new Solution(16,"Java in Action"));
System.out.println(Library.stream()
.map(p->p.getBookName())
.sorted(Comparator.reverseOrder())
.findFirst());
}
出力:Optional[Java in Action]
書籍名は同じでもISBN番号が異なる場合があります。その場合、書籍の並べ替えと検索は非常に似ている可能性がfindAny()
あり、間違った結果になります。5冊の本に「JavaReference」という名前が付いているが、ISBN番号が異なりfindFirst()
、名前による本の結果がと同じになるシナリオを考えてみてくださいfindAny()
。
次のようなシナリオを考えてみてください。
ISBN Name Of book
+-----+------------------+
| 100 | Java-8 in Action |
+-----+------------------+
| 101 | Java-8 in Action |
+-----+------------------+
| 102 | Java-8 in Action |
+-----+------------------+
| 103 | Java-8 in Action |
+-----+------------------+
| 104 | Java-8 in Action |
+-----+------------------+
ここで、findFirst()とfindAny()は、BookByNameで並べ替えても同じ結果になります。
filter
が適用された後でも、適用されfindAny
たフィルターと一致しない要素を含め、任意の要素を返すことができますか?