在处理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之间差异的一个例子",并且接受的答案基本上是"并行流"。这个问题具体是关于顺序流。
答案 0 :(得分:8)
不能保证forEach
终端操作将处理遭遇顺序中的元素,因此“显然是不确定的”。虽然在当前实现中,它应该按流的遇到顺序处理顺序流的元素。
forEachOrdered
主要用于您正在使用并行流的情况,并且如果流具有已定义的遭遇顺序,则希望遵守流的遭遇顺序。
在顺序流上使用forEach
或forEachOrdered
会产生相同的效果,因此需要优先考虑。
如上所述,在当前的实现中,我们知道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}}中对订单保存的明确保证极不可能在将来的版本中被故意破坏。
所以......我会向该应用程序的维护者指出这个错误。我们无法预测它将来会 ,但它当然可以。潜在的错误是错误。