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
非常渴望; 像任何其他有状态的中间操作(如sorted
和distinct
)。 而且很容易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();
这意味着对于每个url
, flatMap
将阻止其后的所有其他操作,即使您关心单个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
方法,您将获得所需的懒惰。 但不是它返回的数据。