当前位置: 首页 > 知识库问答 >
问题:

在Java8中,顺序和有序的流是否保证按照遇到的顺序执行操作?

孔皓
2023-03-14

是否有任何保证在顺序和有序流上的操作是按遇到顺序处理的?

我是说,如果我有这样的代码:

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

是否可以保证它将按照生成范围的遇到顺序执行myFunction()调用?

我找到了Stream类的JavaDocs草案,它明确地说明了以下内容:

对于顺序流管道,如果管道源具有已定义的遇到顺序,则所有操作都按照管道源的遇到顺序执行。

但是它没有提到顺序流,这个例子是针对并行流的(我的理解是,顺序流和并行流都是正确的,但这是我不确定的部分)。

另一方面,它也在订购部分声明:

如果一个流是有序的,那么大多数操作都被限制为按它们遇到的顺序对元素进行操作;如果流的源是包含[1,2,3]列表,则执行映射(x->x*2)的结果必须是[2,4,6]。但是,如果源没有定义的遇到顺序,则[2,4,6]值的任何排列都将是有效的结果。

共有1个答案

牛骞仕
2023-03-14

我想,从这个明确的句子被去掉的事实中,我们可以学到很多东西。这个问题似乎与“Stream.foreach是否尊重顺序流的遇到顺序?”这个问题密切相关。Brian Goetz的回答基本上是这样说的,尽管在顺序流上调用foreach时,流的当前实现不会忽略顺序,但foreach仍然可以自由地忽略遇到的顺序,即使是按照规范对顺序流也是如此。

现在考虑stream的类文档的以下部分:

为了执行计算,流操作被组合到流流水线中。流管道由一个源(可能是数组、集合、生成器函数、I/O通道等)、零个或多个中间操作(将流转换为另一个流,如filter(谓词))和一个终端操作(产生结果或副作用,如count()foreach(消费者))组成。溪水是懒散的;只有在终端操作启动时才执行对源数据的计算,并且只有在需要时才消耗源元素。

由于是终端操作决定了是否需要元素以及是否按照遇到的顺序需要它们,因此终端操作忽略遇到顺序的自由也意味着按照任意顺序消耗元素,从而处理元素。

请注意,不仅foreach可以这样做。收集器能够报告无序特性,例如收集器.toset()不依赖于遇到的顺序。很明显,像count()这样的操作也不依赖于顺序--在Java ;9中,它甚至可以在不进行任何元素处理的情况下返回。另一个例子是intStream#sum()

在过去,实现过于急切地向流上游传播无序特性,请参见“is this a bug In files.lines(),or am I merging something about parallel streams?”,其中终端操作影响skip步骤的结果,这就是当前实现不愿进行此类优化以避免类似bug的原因,但这并不排除此类优化的重现,然后更加小心地实现…

因此,目前很难想象一个实现如何能够从利用顺序流中无序计算的自由中获得性能优势,但是,正如foreach相关问题中所述,这并不意味着任何保证。

 类似资料:
  • 问题内容: 我认为使用某种顺序才有意义。我想做的是在视图中包括该子句,以便该视图上的所有s都可以忽略它。但是,我担心该订单不一定会延续到,因为它没有指定订单。 是否存在一种情况,即视图指定的顺序不会反映在该视图上的select结果中(该视图中的order by子句除外)? 问题答案: 您不能指望没有显式子句的任何查询中的行顺序。如果查询有序视图,但没有包括子句,则如果它们的顺序正确,请感到惊喜,并

  • 问题内容: Javadoc 表示(重点是我): 该操作的行为明确地是不确定的。 对于并行流管道,此操作不能保证遵守流的遇到顺序 ,因为这样做会牺牲并行性的好处。对于任何给定的元素,可以在库选择的任何时间和线程中执行操作。如果操作访问共享状态,则它负责提供所需的同步。 Java 9 Early Access Javadoc中提供了相同的文本。 第一句话(“明确地不确定”)表明(但未明确说明)此方法未

  • 返回的迭代器是否保证按该顺序提供值 、、? 我知道和保证集合的值顺序正确。此外,我并不是在问如何从迭代器生成流。

  • 的Javadoc表示(强调是我的): 此操作的行为显式不确定。对于并行流管道,此操作不能保证尊重流的相遇顺序,因为这样做会牺牲并行性的好处。对于任何给定的元素,操作可以在库选择的任何时间和线程中执行。如果操作访问共享状态,则它负责提供所需的同步。 同样的文本也出现在Java9早期访问Javadoc中。 如果forEach不保留遭遇顺序,则会引入bug。在报告针对NetBeans的bug之前,我想知

  • 我想在Java对象中处理列表。我必须确保处理所有的元素,以便我收到他们。 因此,我是否应该对我使用的每个调用? 或者,只要不使用并行性,只使用流就足够了吗?