我有以下示例代码:
System.out.println(
"Result: " +
Stream.of(1, 2, 3)
.filter(i -> {
System.out.println(i);
return true;
})
.findFirst()
.get()
);
System.out.println("-----------");
System.out.println(
"Result: " +
Stream.of(1, 2, 3)
.flatMap(i -> Stream.of(i - 1, i, i + 1))
.flatMap(i -> Stream.of(i - 1, i, i + 1))
.filter(i -> {
System.out.println(i);
return true;
})
.findFirst()
.get()
);
输出如下:
1
Result: 1
-----------
-1
0
1
0
1
2
1
2
3
Result: -1
从这里我可以看到,在第一种情况下,stream
确实表现得很懒惰--我们使用findFirst()
,所以一旦我们有了第一个元素,我们的过滤lambda就不会被调用。然而,在使用flatMap
的第二种情况下,我们看到尽管找到了满足过滤条件的第一个元素(它只是任何第一个元素,因为lambda总是返回true),流的更多内容仍然通过过滤函数提供。
我试图理解为什么它是这样的,而不是像第一个例子一样计算第一个元素后放弃。任何有用的信息都将不胜感激。
发布于 2015-03-24 17:55:26
输入流的元素一个接一个地懒惰地使用。第一个元素1
由两个flatMap
转换为流-1, 0, 1, 0, 1, 2, 1, 2, 3
,因此整个流只对应于第一个输入元素。嵌套的流通过管道急切地具体化,然后变平,然后馈送到filter
阶段。这解释了您的输出。
上述情况并不是源于一个基本的限制,但它可能会使事情变得更加复杂,从而使嵌套流变得更加懒惰。我怀疑这将是一个更大的挑战,使其性能。
作为比较,Clojure的lazy seqs为每一层嵌套获得另一层包装。由于这种设计,当嵌套执行到极致时,使用StackOverflowError
的操作甚至可能失败。
发布于 2015-11-21 11:58:16
在我的免费StreamEx库中,我介绍了短路收集器。当使用短路收集器(如MoreCollectors.first()
)收集顺序流时,从源中只消耗一个元素。在内部,它是以一种非常糟糕的方式实现的:使用自定义异常来中断控制流。使用我的库,你的样本可以这样重写:
System.out.println(
"Result: " +
StreamEx.of(1, 2, 3)
.flatMap(i -> Stream.of(i - 1, i, i + 1))
.flatMap(i -> Stream.of(i - 1, i, i + 1))
.filter(i -> {
System.out.println(i);
return true;
})
.collect(MoreCollectors.first())
.get()
);
结果如下:
-1
Result: -1
发布于 2021-05-19 15:08:48
虽然JDK-8075939已经在Java11中修复,并回传到10和8u222,但在使用Stream.iterator()
:JDK-8267359时,flatMap()
仍然存在一个边缘情况,即在Java17中仍然存在。
这
Iterator<Integer> it =
Stream.of("a", "b")
.flatMap(s -> Stream
.of(1, 2, 3, 4)
.filter(i -> { System.out.println(i); return true; }))
.iterator();
it.hasNext(); // This consumes the entire flatmapped stream
it.next();
打印
1
2
3
4
而这一点:
Iterator<Integer> it =
Stream.of("a", "b")
.flatMap(s -> Stream
.iterate(1, i -> i)
.filter(i -> { System.out.println(i); return true; }))
.iterator();
it.hasNext();
it.next();
永不终止
https://stackoverflow.com/questions/29229373
复制相似问题