1. 概要

Java 8 Stream APIは、誤解されることが多い2つのメソッド findAny() findFirst()を導入しました。

このクイックチュートリアルでは、これら2つの方法の違いとそれらをいつ使用するかを見ていきます。

2. Using Stream.findAny()

名前が示すように、 findAny()メソッドを使用すると、Streamから任意の要素を検索できます。 遭遇順序に注意を払わずに要素を探しているときに使用します。

このメソッドはOptionalインスタンスを返します。これは、Streamが空の場合は空です。

@Test
public void createStream_whenFindAnyResultIsPresent_thenCorrect() {
    List<String> list = Arrays.asList("A","B","C","D");

    Optional<String> result = list.stream().findAny();

    assertTrue(result.isPresent());
    assertThat(result.get(), anyOf(is("A"), is("B"), is("C"), is("D")));
}

非並列操作では、ストリームの最初の要素を返す可能性が高いですが、これを保証するものではありません。

並列操作を処理するときに最大のパフォーマンスを得るには、結果を確実に判断することはできません。

@Test
public void createParallelStream_whenFindAnyResultIsPresent_thenCorrect()() {
    List<Integer> list = Arrays.asList(1, 2, 3, 4, 5);
    Optional<Integer> result = list
      .stream().parallel()
      .filter(num -> num < 4).findAny();

    assertTrue(result.isPresent());
    assertThat(result.get(), anyOf(is(1), is(2), is(3)));
}

3. Using Stream.findFirst()

findFirst()メソッドは、Streamの最初の要素を検索します。 したがって、シーケンスの最初の要素が特に必要な場合は、このメソッドを使用します。

遭遇順序がない場合、Streamから任意の要素を返します。 java.util.streams パッケージのドキュメントによると、「ストリームには、定義された遭遇順序がある場合とない場合があります。 ソースと中間操作によって異なります。」

戻りタイプもOptionalインスタンスであり、Streamも空の場合は空です。

@Test
public void createStream_whenFindFirstResultIsPresent_thenCorrect() {

    List<String> list = Arrays.asList("A", "B", "C", "D");

    Optional<String> result = list.stream().findFirst();

    assertTrue(result.isPresent());
    assertThat(result.get(), is("A"));
}

findFirst メソッドの動作は、並列シナリオでは変更されません。 遭遇順序が存在する場合、それは常に決定論的に動作します。

4. 結論

この記事では、Java 8 StreamsAPIのfindAny()および findFirst()メソッドについて説明しました。

findAny()メソッドは Stream から任意の要素を返し、 findFirst()メソッドはStreamの最初の要素を返します。

この記事の完全なソースコードとすべてのコードスニペットは、GitHubあります。