是否可以保证在遇到订单中顺序和订购流的操作已处理?< / p>
我的意思是,如果我有这样的代码:
IntStream.range(0, 5)
.map(i -> {
myFunction(i);
return i * 2;
})
.boxed()
.collect(toList());
是否有保证,它会以生成范围的遭遇顺序执行myFunction()调用?
我发现draft JavaDocs for the Stream类明确说明了这一点:
对于顺序流管道,如果管道源具有已定义的遭遇顺序,则所有操作都以管道源的遭遇顺序执行。
但在official JavaDocs这条线被删除了。它现在仅讨论所选方法的遭遇顺序。 副作用段落中的Package java.util.stream doc声明:
即使管道被约束以产生与流源的遭遇顺序一致的结果(例如,
IntStream.range(0,5).parallel().map(x -> x*2).toArray()
必须产生[0, 2, 4, 6, 8]
),也不保证订单其中mapper函数应用于单个元素,或者在什么线程中为给定元素执行任何行为参数。
但它没有说顺序流,示例是并行流(我的理解是顺序和并行流都是如此,但这是我不确定的部分)。
另一方面,它也在Ordering部分说明:
如果订购了流,则大多数操作都被约束为对其遭遇顺序中的元素进行操作;如果流的来源是包含
List
的{{1}},则执行[1, 2, 3]
的结果必须为map(x -> x*2)
。但是,如果源没有定义的遭遇顺序,那么值[2, 4, 6]
的任何排列都将是有效的结果。
但是这次它以“对元素进行操作”开始,但是示例是关于生成的流,所以我不确定它们是否会考虑副作用,副作用实际上是这个问题的关键所在
答案 0 :(得分:1)
我认为我们可以从这个明确的句子被删除的事实中学到很多东西。这个问题似乎与问题“Does Stream.forEach respect the encounter order of sequential streams?”密切相关。 answer from Brian Goetz基本上表示,尽管在顺序流上调用forEach
时,Stream的当前实现没有忽略该顺序的事实,forEach
已经3> em>即使对于每个规范的顺序Streams,也可以自由地忽略遭遇顺序。
现在考虑Stream
’s class documentation的以下部分:
要执行计算,流操作将组成一个流管道。流管道由源(可能是数组,集合,生成器函数,I / O通道等),零个或多个中间操作(将流转换为另一个流)组成,例如
filter(Predicate)
)和终端操作(产生结果或副作用,例如count()
或forEach(Consumer)
)。溪流很懒;源数据的计算仅在启动终端操作时执行,源元素仅在需要时使用。
由于是终端操作确定是否需要元素以及是否在遭遇顺序中需要它们,因此终端动作忽略遭遇顺序的自由也意味着以任意顺序消耗,因此处理元素。
请注意,forEach
不仅可以做到这一点。 Collector
能够报告UNORDERED
特征,例如Collectors.toSet()
不依赖于遭遇顺序。很明显,像count()
这样的操作也不依赖于Java 9中的顺序 - 它甚至可以在没有任何元素处理的情况下返回。想想IntStream#sum()
的另一个例子。
过去,实现过于急于在流中传播无序特征,请参阅“Is this a bug in Files.lines(), or am I misunderstanding something about parallel streams?”终端操作影响skip
步骤结果的原因,这就是< em>当前实现不愿意这样的优化以避免类似的错误,但这并不排除这种优化的再次出现,然后更谨慎地实现......
所以目前很难想象一个实现如何通过在顺序Stream中利用无序评估的自由来获得性能优势,但是,正如forEach
相关问题所述,那不是'这意味着任何保证。