Stream#limit return 元素可以比预期少吗?
Can Stream#limit return fewer elements than expected?
如果下面的 Stream s
至少有 n
个元素,那么在什么情况下 Stream sLimit
可能有少于 n
个元素(如果有)?
Stream sLimit = s.limit(n);
提问原因:在,我看到:
Despite the appearances, using limit(10)
doesn't necessarily result in a SIZED
stream with exactly 10 elements -- it might have fewer.
你误解了这个说法。如果 Stream
至少有 n
个元素并且你在其上调用 limit(n)
,它将恰好有 n
个元素但是 Stream
实现 可能没有意识到这一点,因此性能不尽如人意。
相比之下,某些 Stream
来源 (Spliterator
s) 肯定知道它们具有固定大小,例如创建 Stream
for an array or an IntStream
via IntStream.range
时。它们可以比 Stream
和 limit(n)
.
更好地优化
当您通过 Stream.generate(MyClass::new).limit(10)
创建 parallel
Stream
时,构造函数仍将按顺序调用,只有后续操作可能 运行 并行。相反,当使用 IntStream.range(0, n).mapToObj(i -> new MyClass())
时,整个 Stream
操作,包括构造函数调用,可以 运行 并行。
我认为 Holger 和 Sotirios 的回答是准确的,但鉴于我是发表声明的人,我想我应该解释一下自己。
我主要说的是spliterator characteristics,特别是SIZED
这个特性。这基本上是关于流阶段的 "static" 信息,这些信息在管道设置时已知,但在流实际执行之前。实际上,它用于确定流的执行策略,因此必须在流执行之前知道它。
limit()
操作创建了一个拆分器来包装其上游拆分器,因此 limit
拆分器需要确定要 return 的特征。即使它的上游分裂器是SIZED
,它也不知道确切的大小,所以它不得不关闭SIZED
特性。
所以如果你,程序员,要写:
IntStream.range(0, 100).limit(10)
你会说 当然 流恰好有 10 个元素。 (它会的。)但是生成的拆分器仍然不是 SIZED
。毕竟limit
算子不知道上面和这个的区别:
IntStream.range(0, 1).limit(10)
至少在分离器特性方面。
这就是为什么,尽管有时看起来应该如此,但 limit
运算符并没有 return 已知大小的流。这反过来会影响拆分策略,进而影响并行效率。
如果下面的 Stream s
至少有 n
个元素,那么在什么情况下 Stream sLimit
可能有少于 n
个元素(如果有)?
Stream sLimit = s.limit(n);
提问原因:在
Despite the appearances, using
limit(10)
doesn't necessarily result in aSIZED
stream with exactly 10 elements -- it might have fewer.
你误解了这个说法。如果 Stream
至少有 n
个元素并且你在其上调用 limit(n)
,它将恰好有 n
个元素但是 Stream
实现 可能没有意识到这一点,因此性能不尽如人意。
相比之下,某些 Stream
来源 (Spliterator
s) 肯定知道它们具有固定大小,例如创建 Stream
for an array or an IntStream
via IntStream.range
时。它们可以比 Stream
和 limit(n)
.
当您通过 Stream.generate(MyClass::new).limit(10)
创建 parallel
Stream
时,构造函数仍将按顺序调用,只有后续操作可能 运行 并行。相反,当使用 IntStream.range(0, n).mapToObj(i -> new MyClass())
时,整个 Stream
操作,包括构造函数调用,可以 运行 并行。
我认为 Holger 和 Sotirios 的回答是准确的,但鉴于我是发表声明的人,我想我应该解释一下自己。
我主要说的是spliterator characteristics,特别是SIZED
这个特性。这基本上是关于流阶段的 "static" 信息,这些信息在管道设置时已知,但在流实际执行之前。实际上,它用于确定流的执行策略,因此必须在流执行之前知道它。
limit()
操作创建了一个拆分器来包装其上游拆分器,因此 limit
拆分器需要确定要 return 的特征。即使它的上游分裂器是SIZED
,它也不知道确切的大小,所以它不得不关闭SIZED
特性。
所以如果你,程序员,要写:
IntStream.range(0, 100).limit(10)
你会说 当然 流恰好有 10 个元素。 (它会的。)但是生成的拆分器仍然不是 SIZED
。毕竟limit
算子不知道上面和这个的区别:
IntStream.range(0, 1).limit(10)
至少在分离器特性方面。
这就是为什么,尽管有时看起来应该如此,但 limit
运算符并没有 return 已知大小的流。这反过来会影响拆分策略,进而影响并行效率。