Stream.forEach
的Javadoc(重点是我的)说:
该操作的行为明确是不确定的。 对于并行流水线,此操作不能保证尊重流的遇到顺序,因为这样做将牺牲并行性的好处。 对于任何给定的元素,动作可以在库选择的任何时间和任何线程中执行。 如果操作访问共享状态,则负责提供所需的同步。
相同的文本也出现在Java 9 Early Access Javadoc中。
第一句话(“明确的不确定性”)表明(但并没有明确说明)该方法不保留遇到顺序。 但是下一句话明确说明顺序不被保留,其条件是“对于并行流水线”,如果该句适用于无论是否并行,那么该条件是不必要的。 这使我不确定forEach是否为顺序流保留了遇到顺序。
这个答案指出了一个地方,流库的实现调用.sequential().forEach(downstream)
。这表明forEach旨在保留顺序以适用于串行流,但也可能只是库中的一个错误。
我在自己的代码中通过使用forEachOrdered
来避免这种歧义,但今天我发现NetBeans IDE的“使用函数操作”编辑提示将转换
for (Foo foo : collection)
foo.bar();
转换为
collection.stream().forEach((foo) -> {
foo.bar();
});
如果forEach不保留遇到的顺序,则会引入错误。在我向NetBeans报告错误之前,我想知道该库实际上保证了什么,并由来源支持。
我正在寻找从权威来源得出的答案。这可以是库实现中的明确评论,Java开发邮件列表上的讨论(Google没有为我找到任何内容,但也许我不知道魔法词),或者是库设计师的声明(其中我认识两个人,Brian Goetz和Stuart Marks,他们在Stack Overflow上活跃)。 (请不要回答“只需使用forEachOrdered”-我已经这样做了,但我想知道不使用它的代码是否有问题。)
forEach
忽略所有流的 "ordered" 属性,包括并行/串行、有序/无序。没有例外。即使当前流实现中没有任何代码会导致串行流的非遇到顺序,但该选项保留了未来的可能性。 - zapl.distinct()
使用LinkedHashSet
保留顺序。如果终端操作是forEach
或findAny
,它可以使用简单的HashSet
以减少开销。 - Tagir Valeevcollection.stream().forEach()
而不是简单地使用collection.forEach()
? - shmoselforEach
至少在理论上可以在顺序管道中实现一些相当激进的优化。例如,.sorted().forEach()
可以省略排序。 - the8472