为什么在java 8中使用此代码:
IntStream.range(0, 10)
.peek(System.out::print)
.limit(3)
.count();
输出:
012
我希望它输出0123456789
,因为窥视优先于限制。
在我看来,因为这个事实更加奇特:
IntStream.range(0, 10)
.peek(System.out::print)
.map(x -> x * 2)
.count();
按预期输出0123456789
(不是02481012141618
)。
P.S。:.count()
这里仅用于消费流,它可以替换为其他任何东西
答案 0 :(得分:16)
关于流的最重要的事情是它们本身不包含元素(如集合),但它们的工作方式类似于 lazily 评估的管道。这意味着在终端操作运行之前,不会评估构建流的语句(包括映射,过滤或其他)。
在第一个示例中,流尝试从0到9进行计数,每次执行以下操作:
所以你真的得到了输出012
。
在第二个示例中,流再次从0到9计数,每次执行以下操作:
正如您所看到的那样,输出在映射之前,因此您得到结果0123456789
。尝试切换peek
和map
来电。然后你会得到你期望的输出。
答案 1 :(得分:7)
来自docs:
limit()
是short-circuiting stateful intermediate operation.
map()
是intermediate operation
再次从docs开始,limit()
将从其收到的流中返回一个包含x
值的流。
中间操作是短路的,如果在呈现无限输入时,它可能会产生有限的流。
答案 2 :(得分:4)
Stream
被定义为进行延迟处理。因此,为了完成count()
操作,不需要查看其他项目。否则,它会被破坏,因为limit(…)
被定义为在有限时间内处理无限流的正确方法(通过不处理超过limit
项)。
原则上,可以在不查看int
值的情况下完成您的请求,因为操作链limit(3).count()
不需要对先前操作进行任何处理(除了验证流是否至少有3
个项目。
答案 3 :(得分:2)
Streams使用延迟评估,在终端操作运行之前,不执行中间操作,即 peek()。 例如,以下代码只打印 1 。实际上,只要流的第一个元素1到达终端操作, findAny(),流执行将结束。
Arrays.asList(1,2,3)
.stream()
.peek(System.out::print)
.filter((n)->n<3)
.findAny();
以下示例中的Viceversa将打印 123 。事实上,终端操作 noneMatch()需要评估流的所有元素,以确保与谓词不匹配: n&gt; 4 < / p>
Arrays.asList(1, 2, 3)
.stream()
.peek(System.out::print)
.noneMatch(n -> n > 4);