Java Streams API中的“ forEach”无序是什么原因?

时间:2018-09-14 05:03:37

标签: java java-8 java-stream

据我所知,并行流中,诸如findFirstskiplimit之类的方法只要保持其行为只要无论是否并行,流都是有序的(默认情况下)。所以我想知道为什么forEach方法是不同的。我考虑了一下,但我只是不明白定义forEachOrdered方法的必要性,因为将forEach缺省设置为序,然后调用{{1}在流实例上就是这样,无需定义新方法。

不幸的是,在这一点上,我在Java 8方面的实践经验非常有限,因此,如果有人可以向我解释此架构决定的原因,也许我会通过一些简单的示例/用例向我展示否则可能会出错,我将不胜感激

为了明确起见,我不是在问这个问题:forEach vs forEachOrdered in Java 8 Stream。我完全知道这些方法如何工作以及它们之间的差异。我要问的是Oracle做出体系结构决策的实际原因。

3 个答案:

答案 0 :(得分:3)

当您并行处理Stream的元素时,您应该不要期望在订单上有任何保证。

整个想法是,多个线程在该流的不同元素上工作。它们分别进行,因此处理顺序不可可预测。它是不确定的,又称​​随机

可以想象有意实现该接口的人 会给您随机的顺序,从而使您真正清楚不会有任何期望使用并行流时,顺序不同。

答案 1 :(得分:3)

诸如findFirstlimitskip之类的方法需要输入顺序,因此无论我们使用并行流还是串行流,它们的行为都不会改变。但是,forEach作为一种方法不需要任何顺序,因此其行为是不同的。

对于并行流管道,forEach操作不能保证尊重流的遇到顺序,因为这样做会牺牲并行性的好处。

我还建议不要将findFirstlimitskip与并行流一起使用,因为由于订购并行流所需的开销,这会降低性能。

答案 2 :(得分:3)

定义方法forEach可以保留顺序,而unordered可以破坏顺序,这会使IMO复杂化;仅仅因为unordered只是在流api内部设置标记而已,而标记检查则必须根据某些条件来执行或强制执行。

因此,假设您会这样做:

someStream()
      .unordered()
      .forEach(System.out::println)

在这种情况下,您的建议是不要以任何顺序打印元素,因此在此处强制 unordered。但是,如果我们这样做了:

someSet().stream()
         .unordered()
         .forEach(System.out::println)

在这种情况下,您想强制执行unordered吗?毕竟,流的源是Set,它没有顺序,因此,在这种情况下,强制执行unordered只是没有用。但这意味着要在内部对流的源进行其他测试。这可能会变得非常棘手和复杂(因为它已经是btw)了。

为简化起见,定义了两种方法,明确规定了它们的作用。例如findFirstfindAny 甚至 Optional::isPresentOptional::isEmpty(在Java-11中添加)。 >