flatMap是否保证是懒惰的?

请考虑以下代码:

urls.stream() .flatMap(url -> fetchDataFromInternet(url).stream()) .filter(...) .findFirst() .get(); 

当第一个url足够时, fetchDataFromInternet会为第二个url调用fetchDataFromInternet

我尝试了一个较小的例子,它看起来像预期的那样工作。 即逐个处理数据但是可以依赖这种行为吗? 如果没有,在.flatMap(...)之前调用.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); }); 

输出:

 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 

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

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

如果出现这种情况,API应该让函数返回Iterable而不是stream。

换句话说: 链接

根据目前的实施情况flatmap非常渴望; 像任何其他有状态的中间操作(如sorteddistinct )。 而且很容易certificate:

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

这永远不会完成,因为flatMap是急切计算的。 对于你的例子:

 urls.stream() .flatMap(url -> fetchDataFromInternet(url).stream()) .filter(...) .findFirst() .get(); 

这意味着对于每个urlflatMap将阻止其后的所有其他操作,即使您关心单个url也是如此。 因此,假设从一个url你的fetchDataFromInternet(url)生成10_000行,你的findFirst将必须等待所有 10_000计算,即使你只关心一个。

编辑

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

目前尚不清楚为什么你设置一个不能解决实际问题的例子,你感兴趣的是。如果你想知道,在应用像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)); 
 flatMap function evaluated for "hello" processing element h processing element e processing element l processing element l processing element o found an l 

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

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

Interesting Posts