java – Stream.forEach是否尊重顺序流的遇到顺序?

Stream.forEach的Javadoc说(强调我的):

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 Early Access Javadoc.

第一句话(“显式非确定性”)建议(但不明确说明)遇到的顺序不会被这种方法所保留.但是下一句话,明确地说,命令不被保留,是以“对于并行流管道”为条件的,如果不考虑并行性的话,这个条件是不必要的.这让我不确定是否保持顺序流的顺序.

This answer指出了流库实现calls .sequential().forEach(downstream)的一个地方.这表明forEach旨在保持顺序流的顺序,但也可能只是库中的错误.

我通过使用forEachOrdered安全地在我自己的代码中回避了这种歧义,但是今天我发现NetBeans IDE的“使用功能操作”编辑器提示将转换

for (Foo foo : collection)
    foo.bar();

collection.stream().forEach((foo) -> {
    foo.bar();
});

如果forEach不保存遇到的顺序,它会引入一个错误.在我报告a bug against NetBeans之前,我想知道图书馆实际保证什么,由资料库备份.

我正在寻找从权威来源的答案.这可能是图书馆实施中的一个明确的评论,关于Java开发邮件列表的讨论(Google没有为我找到任何东西,但也许我不知道魔术词),或是图书馆设计师的一个声明知道两个,Brian GoetzStuart Marks,在Stack Overflow上都是活动的). (请不要用“只是使用forEachOrdered”来回答 – 我已经做了,但是我想知道代码不是错的)

存在用于描述调用者可以依赖的最小保证的规范,而不是描述实现的功能.这个差距至关重要,因为它允许实现灵活性发展. (规范是声明性的;实现是必不可少的.)超出规则与下面的规定一样糟糕.

当规范说“不保留属性X”时,并不意味着属性X可能永远不会被观察到;这意味着实施没有义务保存它.你所声称的遇到命令的含义是永远不会被保留的只是一个错误的结论. (HashSet不承诺迭代它的元素保留它们插入的顺序,但这并不意味着这不会意外发生 – 你只是不能指望它.)

同样,您对“每个建议旨在保持顺序流的顺序”的含义,因为您在某些情况下看到一个这样执行的实现同样是错误的.

在这两种情况下,似乎你只是不舒服的事实,这个规定给了很大的自由.具体来说,尽管这是执行目前的做法,但它有自由地不能保持序列流的相遇顺序,而且还有一种难以想象的一种实现方式来处理顺序源不顺序.但是这是规范说的,这就是它的意思.

也就是说,关于并行流的评论的措辞可能令人困惑,因为仍然有可能误解它.这里明确指出并行案例的意图是教学性的;该规范仍然完全清楚,该句完全删除.然而,对于不了解并行性的读者来说,几乎不可能不认为每一个都会保存遇到的顺序,所以添加了这个句子来帮助澄清动机.但是,正如你所指出的那样,特别对待顺序案件的愿望仍然如此强大,进一步澄清是有益的.

翻译自:https://stackoverflow.com/questions/34247318/does-stream-foreach-respect-the-encounter-order-of-sequential-streams

转载注明原文:java – Stream.forEach是否尊重顺序流的遇到顺序?