如果下面的流s
至少有n
个元素,那么流sLimit
可能包含少于n
个元素的情况是什么?
Stream sLimit = s.limit(n);
问题的原因:在this answer中,我读到了:
尽管有外观,但使用
limit(10)
并不一定会产生一个只包含10个元素的SIZED
流 - 它可能会有更少的内容。
答案 0 :(得分:6)
你误解了这句话。如果Stream
至少包含n
个元素并且您在其上调用limit(n)
,那么它将具有n
个Stream
元素,但Stream
实现可能没有意识到它,因此性能不佳。
相比之下,某些Spliterator
来源(IntStream
s)肯定知道它们具有固定的大小,例如通过Stream
for an array创建IntStream.range
或Stream
时。它们的优化程度优于limit(n)
parallel
。
当您通过Stream
创建Stream.generate(MyClass::new).limit(10)
IntStream.range(0, n).mapToObj(i -> new MyClass())
时,仍会按顺序调用构造函数,并且只能并行执行后续操作。相反,使用Stream
时,整个{{1}}操作(包括构造函数调用)可以并行运行。
答案 1 :(得分:5)
我认为Holger&Sotirios'答案是准确的,但因为我是发表声明的人,我想我应该解释一下。
我主要谈论spliterator characteristics,特别是SIZED
特征。这基本上是"静态"有关在流程设置时已知但在流实际执行之前已知的流阶段的信息。实际上,它用于确定流的执行策略,因此必须在流执行之前知道它。
limit()
操作会创建一个包装其上游分裂器的分裂器,因此limit
分裂器需要确定要返回的特征。即使其上游分裂器为SIZED
,它也不知道确切的大小,因此必须关闭SIZED
特征。
所以如果你是程序员,那就写:
IntStream.range(0, 100).limit(10)
你说当然该流正好有10个元素。 (它会。)但是得到的分裂器仍然不是SIZED
。毕竟,limit
运营商并不知道上述与此之间的区别:
IntStream.range(0, 1).limit(10)
至少在分裂者特征方面。
这就是为什么,即使有时它看起来应该如此,limit
运算符也不会返回已知大小的流。这反过来又会影响分裂策略,从而影响并行效率。