java stream 有序_关于java:Stream.forEach是否遵循顺序流的遭遇顺序?

javadoc forStream.forEach表示(emphasis mine):

The behavior of this operation is explicitly nondeterministic. For parallel stream pipelines, this operation does not guarantee to respect the encounter order of the stream, as doing so would sacrifice the benefit of parallelism. For any given element, the action may be performed at whatever time and in whatever thread the library chooses. If the action accesses shared state, it is responsible for providing the required synchronization.

Java 9早期访问JavaDoc中存在相同的文本。

第一句话("显式不确定性")表明(但没有显式地说)这种方法不保留遭遇顺序。但是,下一个明确表示顺序不被保留的语句是以"用于并行流管道"为条件的,如果不管并行性如何,应用该语句,则不需要这种条件。这让我不确定foreach是否保留了遇到顺序流的顺序。

这个答案指出了流库实现调用.sequential().forEach(downstream)的地方。这表明foreach旨在为顺序流保留顺序,但也可能只是库中的一个bug。

我在自己的代码中使用了安全方面的forEachOrdered避免了这种模糊性,但今天我发现netbeans ide的"use functional operations"编辑器提示将转换

for (Foo foo : collection)

foo.bar();

进入之内

collection.stream().forEach((foo) -> {

foo.bar();

});

如果foreach不保留遭遇顺序,则会引入一个bug。在我报告一个针对NetBeans的bug之前,我想知道库实际上保证了什么,由一个源进行备份。

我在找权威人士的答案。这可能是库实现中的一个明确的评论,关于Java开发邮件列表的讨论(谷歌找不到任何东西,但也许我不知道这些神奇的单词),或者来自图书馆设计者(我知道两个,Brian Goetz和斯图亚特马克)的声明是活跃的。堆栈溢出)。(请不要用"只使用foreachored代替"——我已经这样做了,但我想知道代码是否正确。)

文件很清楚。forEach忽略所有流的"有序"属性,并行/顺序、有序/无序。也不例外。即使当前流实现中没有代码会导致顺序流的非偶遇顺序,该选项仍将为将来打开。

问题实际上更深层:无序的流特征对于连续的流是否重要(或者将来可能重要)。目前,顺序无序流总是按顺序处理,但当源或终端操作无序时,可以执行许多优化。例如,.distinct()使用LinkedHashSet来保留顺序。如果终端OP是forEach或findAny的话,它可以简单地使用开销较小的HashSet。

此外,即使在没有按顺序处理的情况下,也通常认为按顺序处理是必要的。这是我们成长过程中普遍存在的后遗症的副作用;有序是如此容易,如此廉价,如此之久以至于我们很容易不去质疑这样一个假设,即它是必要的,即使它不是必要的。

我提交了netbeans bug 257129。

Netbeans真的做到了吗?为什么您要调用collection.stream().forEach()而不是简单地调用collection.forEach()?

我认为,至少理论上,即使在顺序管道中,也能实现一些相当积极的优化。例如,可以省略排序。

(P)Specifications exist to describe the minimal guarantees a caller can depend on,not to describe what the implementation does.这一差距是至关重要的,因为它是执行灵活性的一部分。(specification is declarative;implementation is imperative.)overspecification is just bad as underspecification.(p)(P)当具体说明"不保全财产X"时,它并不意味着该财产X可能永远得不到遵守;它意味着执行不是维护该财产的义务。你所声称的含义是,鼓励的秩序绝不会仅仅是一个错误的结论。((p)(P)Similarly,your implication of"that suggests foreach is intended to conserve order for sequential streams"because you saw an implementation that does in some case is equally imperror.(p)(P)In both cases,it seems like you're just uncomfortable with the fact that the specification givesa great deal of freedom.Specifically,it has the freedom to not preserve encounter order for sequential streams,even though that's what the implementation currently does,and further that it's kind of hard to image an implementation going out of it s way to process sequential sources out of order.但他说的是什么,他想说什么。(p)(P)That said,the wording of the comment about parallel streams is potentially confusing,because it is still possible to misinterpret it.The intent of calling out the parallel case explicitly here was educatical;the SPEC is still perfectly clear with that sentence removed entirely.然而,为了让人们了解谁是一个平行的群体,这将是不可接受的,以便不保证以下一点:将维护Encounter Order,因此,这一判决将补充到帮助Clarify the Motivation。但是,由于你不在,处理这类具体案件的决定仍然很有可能对Clarify Further有益。(p)

我完全同意允许实现自由的规范。我只是想要一个明确的声明,所以我不必和NetBeans开发人员争论他们的bug。(至于"从不",我在想"不管溪流是否有序",而不是"必须改变秩序"。当然,无序流也没有保存的顺序。)除了澄清文本之外,添加@see forEachOrdered可能会向开发人员显示还有一个选择。

@是的,那也会有帮助的。这里的关键问题(这显然比看起来更难,因为我们第一次没有100%正确地理解)是帮助人们克服他们普遍存在的顺序偏见。甚至"有一个明确的遭遇顺序"的概念也让很多人困惑!

我认为可以通过删除第二句中的"保证"来澄清意图。这更清楚地表明,它是一个实现说明,而不是并行流特有的规范细节。

@基于经验,我不认为这是一个澄清,我只是认为它会混淆不同的人群比目前的版本。如果它说"不尊重",一些人肯定会认为我们会不顾一切地不尊重这个顺序,这与迭代顺序是随机的集合不同。(为1000万人将要使用的东西编写规范并不是那么容易。这听起来可能很荒谬,但我们总是看到这样的东西。)

我听到了,但我仍然认为这在客观上更正确。不管怎样,当我把您带到这里时,关于线程安全的下一句话是否也适用于顺序流?如果是,为什么?为什么要让规范如此松散和违反直觉?

@shmosel只需编写清晰捕获语义期望的代码如何?如果您关心遭遇顺序,只需使用forEachOrdered,现在您的代码就清楚了。而在顺序流上打开的成本并不比打开的成本高。从根本上说,我认为你是在说"请不要让我解释像排序这样的硬概念。"对于一个支持低仪式并行性的框架,我认为这不会对任何人有好处。

你可能感兴趣的:(java,stream,有序)