Stream#limit可以返回比预期更少的元素吗?

ass*_*ias 4 java java-8 java-stream

如果s下面的流至少包含n元素,那么流sLimit可能具有少于n元素的情况是什么?

Stream sLimit = s.limit(n);
Run Code Online (Sandbox Code Playgroud)

问题的原因:在这个答案中,我读到:

尽管有外观,但使用limit(10)并不一定会产生一个只SIZED包含10个元素的流 - 它可能会少一些.

Hol*_*ger 6

你误解了这个陈述.如果Stream至少包含n元素并且您limit(n)在其上调用它,它将具有确切的n元素,但Stream 实现可能不会意识到它,因此具有不太理想的性能.

相比之下,某些StreamSpliterator确定它们具有固定的大小,例如在创建Stream阵列IntStream通道时IntStream.range.他们可以优化比一个更好Streamlimit(n).

创建parallel Streamvia时Stream.generate(MyClass::new).limit(10),仍将按顺序调用构造函数,并且只能并行运行后续操作.相反,在使用时IntStream.range(0, n).mapToObj(i -> new MyClass()),整个Stream操作(包括构造函数调用)可以并行运行.


Stu*_*rks 5

我认为Holger和Sotirios的答案是准确的,但因为我是发表声明的人,我想我应该自己解释一下.

我主要谈论的是分裂器特性,特别是SIZED特性.这基本上是关于流阶段的"静态"信息,这些信息在流水线设置时已知,但在流实际执行之前.实际上,它用于确定流的执行策略,因此必须在流执行之前知道它.

limit()操作创建了一个包裹其上游分裂器的分裂器,因此limit分裂器需要确定要返回的特征.即使它的上游分裂器是SIZED,它也不知道确切的大小,因此必须关闭该SIZED特性.

所以如果你是程序员,那就写:

IntStream.range(0, 100).limit(10)
Run Code Online (Sandbox Code Playgroud)

当然会说这个流有10个元素.(而且它会.)但是由此产生的分裂者仍然没有SIZED.毕竟,limit运营商不知道上述与此之间的区别:

IntStream.range(0, 1).limit(10)
Run Code Online (Sandbox Code Playgroud)

至少在分裂器特性方面.

所以这就是为什么,即使有时它似乎应该如此,limit操作员也不会返回已知大小的流.这又会影响分裂策略,从而影响并行效率.