简体   繁体   English

在Java 8中,顺序和有序流保证按顺序执行操作吗?

[英]In Java 8, does a sequential and ordered Stream guarantee performing operations in encounter order?

Is there any guarantee that operations on a sequential and ordered Stream are processed in encounter order ? 是否有一个顺序和操作有序流在遭遇顺序 处理任何保证?

I mean, if I have code like this: 我的意思是,如果我有这样的代码:

IntStream.range(0, 5)
        .map(i -> {
            myFunction(i);
            return i * 2;
         })
         .boxed()
         .collect(toList());

is there a guarantee, that it will perform myFunction() calls in the encounter order of the generated range? 是否有保证,它将以生成范围的遭遇顺序执行myFunction()调用?

I found draft JavaDocs for the Stream class which explicitely states this: 我找到了Stream类的JavaDocs草案 ,明确说明了这一点:

For sequential stream pipelines, all operations are performed in the encounter order of the pipeline source, if the pipeline source has a defined encounter order. 对于顺序流管道,如果管道源具有已定义的遭遇顺序,则所有操作都以管道源的遭遇顺序执行。

but in the official JavaDocs this line was removed. 但在官方JavaDocs中,这一行被删除了。 It now discusses encounter order only for selected methods. 它现在仅讨论所选方法的遭遇顺序。 The Package java.util.stream doc in the Side-effects paragraph states: Side-effects段落中的Package java.util.stream doc说明:

Even when a pipeline is constrained to produce a result that is consistent with the encounter order of the stream source (for example, IntStream.range(0,5).parallel().map(x -> x*2).toArray() must produce [0, 2, 4, 6, 8] ), no guarantees are made as to the order in which the mapper function is applied to individual elements, or in what thread any behavioral parameter is executed for a given element. 即使管道被约束产生的结果与流源的遭遇顺序一致(例如, IntStream.range(0,5).parallel().map(x -> x*2).toArray()必须产生[0, 2, 4, 6, 8] ),不保证映射器函数应用于单个元素的顺序,或者对给定元素执行任何行为参数的线程。

but it says nothing about sequential streams and the example is for a parallel stream (My understanding is that it's true for both sequential and parallel streams, but this is the part I'm not sure about). 但它没有说明顺序流,而且这个例子是针对并行流的(我的理解是顺序流和并行流都是如此,但这是我不确定的部分)。

On the other hand, it also states in the Ordering section: 另一方面,它也在订购部分说明:

If a stream is ordered, most operations are constrained to operate on the elements in their encounter order; 如果订购了流,则大多数操作都被约束为对其遭遇顺序中的元素进行操作; if the source of a stream is a List containing [1, 2, 3] , then the result of executing map(x -> x*2) must be [2, 4, 6] . 如果流的源是包含[1, 2, 3]List ,那么执行map(x -> x*2)必须是[2, 4, 6] However, if the source has no defined encounter order, then any permutation of the values [2, 4, 6] would be a valid result. 但是,如果源没有定义的遭遇顺序,那么值[2, 4, 6]任何排列都将是有效的结果。

but this time it start with "operating on the elements", but the example is about the resulting stream, so I'm not sure they are taking side-effects in account and side-effects is really what this question is about. 但这一次它以“对元素进行操作”开始,但是示例是关于产生的流,所以我不确定它们是否会考虑副作用,副作用实际上就是这个问题。

I think we can learn a lot from the fact that this explicit sentence has been removed. 我认为我们可以从这个明确的句子被删除的事实中学到很多东西。 This question seems to be closely related to the question “Does Stream.forEach respect the encounter order of sequential streams?” . 这个问题似乎与“Stream.forEach是否遵守顺序流的遭遇顺序?”这一问题密切相关。 The answer from Brian Goetz basically says that despite the fact that there's no scenario where the order is ignored by the Stream's current implementation when forEach is invoked on a sequential Stream, forEach has the freedom to ignore the encounter order even for sequential Streams per specification. Brian Goetz答案基本上说,尽管在顺序Stream上调用forEach时,Stream的当前实现没有忽略顺序的事实, forEach 可以自由地忽略遇到顺序,即使是每个规范的顺序Streams也是如此。

Now consider the following section of Stream 's class documentation : 现在考虑Stream的类文档的以下部分:

To perform a computation, stream operations are composed into a stream pipeline . 为了执行计算,流操作被组合成流管道 A stream pipeline consists of a source (which might be an array, a collection, a generator function, an I/O channel, etc), zero or more intermediate operations (which transform a stream into another stream, such as filter(Predicate) ), and a terminal operation (which produces a result or side-effect, such as count() or forEach(Consumer) ). 流管道由源(可能是数组,集合,生成器函数,I / O通道等),零个或多个中间操作 (将流转换为另一个流,如filter(Predicate) )和终端操作(产生结果或副作用,例如count()forEach(Consumer) )。 Streams are lazy; 溪流很懒; computation on the source data is only performed when the terminal operation is initiated, and source elements are consumed only as needed. 仅在启动终端操作时执行对源数据的计算,并且仅在需要时消耗源元素。

Since it is the terminal operation which determines whether elements are needed and whether they are needed in the encounter order, a terminal action's freedom to ignore the encounter order also implies consuming, hence processing, the elements in an arbitrary order. 由于终止操作确定是否需要元素以及在遭遇顺序中是否需要元素,因此终端动作忽略遭遇顺序的自由也意味着以任意顺序消耗,因此处理元素。

Note that not only forEach can do that. 请注意,不仅forEach都能做到这一点。 A Collector has the ability to report an UNORDERED characteristic, eg Collectors.toSet() does not depend on the encounter order. Collector能够报告UNORDERED特征,例如Collectors.toSet()不依赖于遭遇顺序。 It's obvious that also an operation like count() doesn't depend on the order—in Java 9 it may even return without any element processing. 很明显,像count()这样的操作也不依赖于Java 9中的顺序 - 它甚至可以在没有任何元素处理的情况下返回。 Think of IntStream#sum() for another example. 想想IntStream#sum()的另一个例子。

In the past, the implementation was too eager in propagating an unordered characteristic up the stream, see “Is this a bug in Files.lines(), or am I misunderstanding something about parallel streams?” where the terminal operation affected the outcome of a skip step, which is the reason why the current implementation is reluctant about such optimizations to avoid similar bugs, but that doesn't preclude the reappearance of such optimizations, then being implemented with more care… 在过去,实现过于急于在流中传播无序特征,请参阅“这是Files.lines()中的错误,还是我误解了有关并行流的内容?”终端操作影响了结果skip步骤,这就是为什么当前的实现不希望这样的优化以避免类似的错误的原因,但这并不排除这种优化的再现,然后更谨慎地实现...

So at the moment it's hard to imagine how an implementation could ever gain a performance benefit from exploiting the freedom of unordered evaluations in a sequential Stream, but, as stated in the forEach -related question, that doesn't imply any guarantees. 因此,目前很难想象一个实现如何通过在顺序流中利用无序评估的自由来获得性能优势,但是,正如forEach相关问题所述,这并不意味着任何保证。

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM