Stream.sorted()。forEach()是否按预期工作?

时间:2017-12-31 20:35:16

标签: java java-stream language-lawyer

在处理Java项目时,我遇到了类似这样的代码:

someMap.keySet().stream().sorted().forEach(/* ... */);

这里的意图显然是为地图中的每个键做一些事情,根据键'自然秩序,这似乎是在实践中发生的事情。但是,我不确定这种行为是否得到保证。 The Javadoc for Stream#forEach说:

  

此操作的行为明确是不确定的。对于并行流管道,此操作不保证遵守流的遭遇顺序,因为这样做会牺牲并行性的好处。对于任何给定元素,可以在任何时间以及库选择的任何线程中执行操作。

我知道如果代码使用的是.parallelStream()而不是.stream(),那么它将无法保证正常工作,但由于它使用的是顺序流(Javadoc没有使用#39}我说什么,我不确定。这是保证始终有效,还是代码需要使用.forEachOrdered()而不是.forEach()

编辑:我认为这个问题不是forEach vs forEachOrdered in Java 8 Stream的重复,因为这个问题要求"什么是forEach和forEachOrdered之间差异的一个例子",并且接受的答案基本上是"并行流"。这个问题具体是关于顺序流。

3 个答案:

答案 0 :(得分:8)

不能保证forEach终端操作将处理遭遇顺序中的元素,因此“显然是不确定的”。虽然在当前实现中,它应该按流的遇到顺序处理顺序流的元素。

forEachOrdered主要用于您正在使用并行流的情况,并且如果流具有已定义的遭遇顺序,则希望遵守流的遭遇顺序。

在顺序流上使用forEachforEachOrdered会产生相同的效果,因此需要优先考虑。

如上所述,在当前的实现中,我们知道forEach终端操作应该按照流的遭遇顺序处理顺序流的元素,但由于它没有在java doc中声明,所以最好坐下来如果您真的关心迭代顺序,请使用forEachOrdered

答案 1 :(得分:4)

在当前的实现下它是 - 但文档非常清楚,不要将其指定为规则。这显然可以改变,但目前它没有改变,即使在做:

Stream.of(5, 4, 3, 1)
      .unordered()
      .forEach(System.out::println);

即使您是故意破坏订单,对于顺序流,数据也不会在内部故意 - 至少目前不是。

你必须要小心,不要依赖它,因为版本之间可能会发生变化,here is one example

答案 2 :(得分:0)

  

这是否保证始终有效,或者该代码是否需要使用.forEachOrdered()而不是.forEach()?

没有。不保证始终有效。正如javadoc所说,.forEachOrdered()方法可能不具有确定性。这意味着实现者有权更改当前确定性的案例以使其行为不同。

如果您需要保证确定性,请使用javadoc明确保证的方法。 {{1}}中对订单保存的明确保证极不可能在将来的版本中被故意破坏。

所以......我会向该应用程序的维护者指出这个错误。我们无法预测它将来会 ,但它当然可以。潜在的错误是错误。