1.概要

Java 8 Stream API中有两个经常被混淆和误用的方法: FindAny()findFirst()

本教程中,我们将对比这两种方法的差异,以及何时使用它们。

2.使用 stream.FindAny()

顾名思义, FindAny() 返回 stream 中任意一个元素:

如果 Stream 为空,则该方法返回为空的 Optional 实例:

@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")));
}

在串行流中,大多数情况下会返回第一个元素,但并不绝对保证

在并行流下,为了获得最佳性能,此时得到的结果不可预测,findAny 通常会返回最快处理完的那个线程的数据:

@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.使用 stream.findFirst()

findfirst() 每次都会返回stream中的第一个元素。

当遇到非 encounter order 流时,它会返回stream中的任何元素。 java.util.streams 文档中提到:

某些流的返回的元素是有确定顺序的,我们称之为 encounter order。这个顺序是流提供它的元素的顺序,比如数组的encounter order是它的元素的排序顺序,List是它的迭代顺序(iteration order),对于HashSet,它本身就没有encounter order。 一个流是否是encounter order主要依赖数据源和它的中间操作。

返回类型也是一个 Optional 实例:

@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"));
}

4.总结

在本教程中,我们研究了Java 8 stream API的 findAny()findFirst() 方法。 findAny() 方法返回流中任何元素,而 findFirst() 方法返回流中的第一个元素。

本文完整源代码存放在GitHub