Stream.forEach是否遵循顺序流的遭遇顺序? [英] Does Stream.forEach respect the encounter order of sequential streams?

查看:423
本文介绍了Stream.forEach是否遵循顺序流的遭遇顺序?的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

Stream.forEach 说(强调我的):

The Javadoc for Stream.forEach says (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 Early Access Javadoc

第一句话(明确不确定)暗示(但没有明确说明)此方法不会保留遭遇顺序。但下一句明确表示顺序未被保留的句子以For parallel stream pipeline为条件,如果不管并行性如何应用该句子,则不需要该条件。这让我不确定forEach是否会保留顺序流的顺序。

The first sentence ("explicitly nondeterministic") suggests (but doesn't explicitly say) that encounter order is not preserved by this method. But the next sentence, that explicitly says order is not preserved, is conditioned on "For parallel stream pipelines", and that condition would be unnecessary if the sentence applied regardless of parallelism. That leaves me unsure whether forEach preserves encounter order for sequential streams.

这个答案指出了流库实现的位置调用 .sequential()。forEach(下游) 。这表明forEach旨在保留顺序流的顺序,但也可能只是库中的一个错误。

This answer points out a spot where the streams library implementation calls .sequential().forEach(downstream). That suggests forEach is intended to preserve order for sequential streams, but could also just be a bug in the library.

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

I've sidestepped this ambiguity in my own code by using forEachOrdered to be on the safe side, but today I discovered that NetBeans IDE's "use functional operations" editor hint will convert

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

进入

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

如果forEach不保留遭遇订单,则会引入错误。在我报告针对NetBeans的错误之前,我想知道该库实际上保证了什么,由来源支持。

which introduces a bug if forEach does not preserve encounter order. Before I report a bug against NetBeans, I want to know what the library actually guarantees, backed up by a source.

我正在寻找权威来源的答案。这可能是图书馆实施中的明确评论,关于Java开发邮件列表的讨论(谷歌没有找到任何东西,但我可能不知道这些神奇的词汇),或者是图书馆设计师的声明(其中我知道两个, Brian Goetz Stuart Marks ,在Stack Overflow上有效。 (请不要回答只是使用forEachOrdered - 我已经这样做了,但我想知道代码是否错误。)

I'm looking for an answer drawing from authoritative sources. That could be an explicit comment in the library implementation, discussion on the Java development mailing lists (Google didn't find anything for me but maybe I don't know the magic words), or a statement from the library designers (of which I know two, Brian Goetz and Stuart Marks, are active on Stack Overflow). (Please do not answer with "just use forEachOrdered instead" -- I already do, but I want to know if code that doesn't is wrong.)

推荐答案

存在一些规范来描述调用者可以依赖的最小保证,而不是描述实现的作用。这种差距至关重要,因为它允许实施灵活性发展。 (规范是声明性的;实现是必要的。)过度规范与指定一样糟糕。

Specifications exist to describe the minimal guarantees a caller can depend on, not to describe what the implementation does. This gap is crucial, as it allows the implementation flexibility to evolve. (Specification is declarative; implementation is imperative.) Overspecification is just as bad as underspecification.

当规范说不保留属性X时,并不意味着可能永远不会观察到属性X;这意味着实施没有义务保留它。您所声称的遭遇订单永远不会被保留,这只是一个错误的结论。 ( HashSet 不保证迭代其元素会保留它们的插入顺序,但这并不意味着这不会意外发生 - 你只是无法计算在它上面。)

When a specification says "does not preserve property X", it does not mean that the property X may never be observed; it means the implementation is not obligated to preserve it. Your claimed implication that encounter order is never preserved is simply a wrong conclusion. (HashSet doesn't promise that iterating its elements preserves the order they were inserted, but that doesn't mean this can't accidentally happen -- you just can't count on it.)

同样,你暗示这意味着forEach旨在保留顺序流的顺序因为你看到一个实现在某些情况下这样做同样如此不正确。

Similarly, your implication of "that suggests forEach is intended to preserve order for sequential streams" because you saw an implementation that does so in some case is equally incorrect.

在这两种情况下,您似乎对规范给出 forEach 这一事实感到不舒服很大的自由。具体来说,它可以自由地保留顺序流的遭遇顺序,即使这是实现当前所做的事情,而且很难想象一个实现不按顺序处理顺序源的方式。但这就是规范所说的,而这就是它的意图。

In both cases, it seems like you're just uncomfortable with the fact that the specification gives forEach a 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 imagine an implementation going out of its way to process sequential sources out of order. But that's what the spec says, and that's what it was intended to say.

这就是说,关于并行流的评论的措辞可能令人困惑,因为它仍然是有可能误解它。这里明确指出并行案例的意图是教学法;该规则仍然完全清楚,完全删除了该句子。但是,对于不知道并行性的读者来说,几乎不可能假设 forEach 会保留遭遇顺序,所以这句话是添加以帮助澄清动机。但是,正如你所指出的那样,特别对待序贯案件的愿望仍然非常强大,以便进一步澄清是有益的。

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 pedagogical; the spec is still perfectly clear with that sentence removed entirely. However, to a reader who is unaware of parallelism, it would be almost impossible to not assume that forEach would preserve encounter order, so this sentence was added to help clarify the motivation. But, as you point out, the desire to treat the sequential case specially is still so powerful that it would be beneficial to clarify further.

这篇关于Stream.forEach是否遵循顺序流的遭遇顺序?的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆