关于java:Stream.sorted()。forEach()是否按预期工作?

Does Stream.sorted().forEach() work as intended?

本问题已经有最佳答案,请猛点这里访问。

在处理Java项目时,我遇到了如下所示的代码:

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

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

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.

我知道如果代码使用.parallelStream()而不是.stream(),它将不能保证工作,但由于它使用顺序流(Javadoc没有说什么),我不是当然。这可以保证始终有效吗,或者该代码是否需要使用.forEachOrdered()而不是.forEach()

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


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

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

在顺序流上使用forEachforEachOrdered将具有相同的效果,因此这是一个偏好问题。

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


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

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

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

你必须要小心,不要依赖它,因为版本之间的事情可以改变,这是一个例子


Is this guaranteed to always work, or would that code need to be using .forEachOrdered() instead of .forEach() for it to be?

不,不能保证始终有效。正如javadoc所说,forEach()方法可能不具有确定性。这意味着实现者拥有更改当前确定性的案例以获得不同行为的许可。

如果您需要保证确定性,请使用javadoc明确保证的方法。在未来的版本中,.forEachOrdered()中明确保证订单保存的可能性是非常不可能的。

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