【发布时间】:2018-02-27 13:24:34
【问题描述】:
考虑以下代码:
urls.stream()
.flatMap(url -> fetchDataFromInternet(url).stream())
.filter(...)
.findFirst()
.get();
当第一个网址足够时,是否会为第二个网址调用fetchDataFromInternet?
我尝试了一个较小的示例,它看起来像预期的那样工作。即一个一个地处理数据,但可以依赖这种行为吗?如果没有,在.flatMap(...) 之前调用.sequential() 有帮助吗?
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
回答: 根据 cmets 和下面的答案,flatmap 是部分懒惰的。即完全读取第一个流,并且仅在需要时才进行下一个。读取流是急切的,但读取多个流是懒惰的。
如果这种行为是有意的,API 应该让函数返回 Iterable 而不是流。
换句话说:link
【问题讨论】:
-
parallelism 上的文档说“当您创建流时,除非另有说明,否则它始终是串行流。”因此不需要调用
.sequential()。 -
是什么让你认为它不是?
-
@pedromss 文档没有明确说明。 docs.oracle.com/javase/8/docs/api/java/util/stream/… 看起来它可能不会偷懒的情况很少:stackoverflow.com/questions/29229373/…
-
@balki 您链接的 SO 帖子在接受的答案中指出中间操作总是惰性的。此外,来自documentation:“流是惰性的;仅在启动终端操作时才对源数据进行计算,并且仅在需要时使用源元素。” Flatmap 是一个中间操作
-
fetchDataFromInternet不会被不必要地调用,但特定fetchDataFromInternet调用返回的元素可能会在没有惰性的情况下得到处理。
标签: java java-8 java-stream flatmap