flatMap是否保证是懒惰的?

bal*_*lki 11 java java-8 java-stream flatmap

请考虑以下代码:

urls.stream()
    .flatMap(url -> fetchDataFromInternet(url).stream())
    .filter(...)
    .findFirst()
    .get();
Run Code Online (Sandbox Code Playgroud)

fetchDataFromInternet当第一个足够的时候会被叫第二个网址吗?

我尝试了一个较小的例子,看起来像预期的那样工作.即逐个处理数据但是可以依赖这种行为吗?如果没有,请.sequential().flatMap(...)帮助前打电话吗?

    Stream.of("one", "two", "three")
            .flatMap(num -> {
                System.out.println("Processing " + num);
                // return FetchFromInternetForNum(num).data().stream();
                return Stream.of(num);
            })
            .peek(num -> System.out.println("Peek before filter: "+ num))
            .filter(num -> num.length() > 0)
            .peek(num -> System.out.println("Peek after filter: "+ num))
            .forEach(num -> {
                System.out.println("Done " + num);
            });
Run Code Online (Sandbox Code Playgroud)

输出:

Processing one
Peek before filter: one
Peek after filter: one
Done one
Processing two
Peek before filter: two
Peek after filter: two
Done two
Processing three
Peek before filter: three
Peek after filter: three
Done three
Run Code Online (Sandbox Code Playgroud)

更新:如果在实施方面很重要,请使用官方Oracle JDK8

:根据以下评论和答案,flatmap部分是懒惰的.即完全读取第一个流,只有在需要时才会读取下一个流.阅读流是急切的,但阅读多个流是懒惰的.

如果出现此行为,API应该让函数返回Iterable而不是流.

换句话说:链接

Eug*_*ene 11

在目前的实施下,flatmap是渴望; 像任何其他有状态的中间操作(如sorteddistinct).而且很容易证明:

 int result = Stream.of(1)
            .flatMap(x -> Stream.generate(() -> ThreadLocalRandom.current().nextInt()))
            .findFirst()
            .get();

    System.out.println(result);
Run Code Online (Sandbox Code Playgroud)

这永远不会像flatMap急切计算的那样完成.对于你的例子:

urls.stream()
    .flatMap(url -> fetchDataFromInternet(url).stream())
    .filter(...)
    .findFirst()
    .get();
Run Code Online (Sandbox Code Playgroud)

这意味着,对于每个人来说,即使您关心一个人url,flatMap也会阻止其后的所有其他操作.因此,让我们假设从单一urlfetchDataFromInternet(url)生成10_000线,以及你findFirst将不得不等待所有被计算10_000,即使你只关心一个.

编辑

这在Java 10中得到修复,我们在这里得到了懒惰:请参阅JDK-8075939


Hol*_*ger 5

目前尚不清楚为什么你设置一个不能解决实际问题的例子,你感兴趣的.如果你想知道,在应用短路操作时处理是否很懒findFirst(),那么请使用一个例子findFirst()而不是forEach那个处理所有元素.此外,将日志记录语句放入要跟踪其评估的函数中:

Stream.of("hello", "world")
      .flatMap(s -> {
          System.out.println("flatMap function evaluated for \""+s+'"');
          return s.chars().boxed();
      })
      .peek(c -> System.out.printf("processing element %c%n", c))
      .filter(c -> c>'h')
      .findFirst()
      .ifPresent(c -> System.out.printf("found an %c%n", c));
Run Code Online (Sandbox Code Playgroud)
flatMap function evaluated for "hello"
processing element h
processing element e
processing element l
processing element l
processing element o
found an l
Run Code Online (Sandbox Code Playgroud)

这表明传递给的函数flatMap按预期延迟评估,而返回的(子)流的元素不会被评估为尽可能懒惰,正如您自己链接的问答中所讨论的那样.

因此,关于fetchDataFromInternet从传递给函数调用的方法flatMap,您将获得所需的懒惰.但不是它返回的数据.


归档时间:

查看次数:

1304 次

最近记录:

6 年,5 月 前