Stream.sorted().forEach() 是不是按预期工作? [复制]

Posted

技术标签:

【中文标题】Stream.sorted().forEach() 是不是按预期工作? [复制]【英文标题】:Does Stream.sorted().forEach() work as intended? [duplicate]Stream.sorted().forEach() 是否按预期工作? [复制] 【发布时间】:2018-06-11 05:55:09 【问题描述】:

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

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

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

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

我知道,如果代码使用 .parallelStream() 而不是 .stream(),则不能保证它可以工作,但由于它使用的是顺序流(Javadoc 没有说明),我'不确定。这是否保证始终有效,或者该代码是否需要使用 .forEachOrdered() 而不是 .forEach() 才能使用?

编辑:我相信这个问题不是 forEach vs forEachOrdered in Java 8 Stream 的重复,因为这个问题是在问“forEach 和 forEachOrdered 之间的区别一般是什么例子”,并且接受的答案基本上是“并行流”。这个问题专门针对顺序流。

【问题讨论】:

streams API是Java的函数式编程接口。在函数式编程中,基本思想是元素之间没有任何关系。甚至顺序也无所谓。顺序可能只对 display 很重要,但对单个元素的任何处理都不重要,就像您对 forEach() 所做的那样。 事实上,如果使用forEach,这将是一个很好的优化——因此是一个无序的管道——优化了排序。 【参考方案1】:

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

没有。不能保证始终有效。正如 javadoc 所说,forEach() 方法可能不是确定性的。这意味着实施者有权更改当前确定性的案例以采取不同的行为。

如果您想要保证确定性,请使用 javadoc 明确保证的方法。在未来的版本中,.forEachOrdered() 中对订单保存的明确保证极不可能被故意破坏。


所以...我会向该应用程序的维护者指出这个错误。我们无法预测它在未来崩溃,但它肯定可以。潜在的错误就是错误。

【讨论】:

【参考方案2】:

不保证forEach 终端操作会按遇到顺序处理元素,因此“显式地不确定”。尽管在当前实现下,它应该按照流的遇到顺序处理顺序流的元素。

forEachOrdered 主要适用于您使用并行流并希望在流具有已定义的遇到顺序的情况下遵守流的遇到顺序的情况。

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

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

【讨论】:

它目前提供了这种行为,我希望它总是会这样做,但由于合同中没有保证,我不会依赖它。我同意this answer。如果您关心迭代顺序,请使用表示您关心迭代顺序的方法。除了为自己节省 7 个字符之外,实际上没有理由不这样做。 @Michael 这实际上是一个好点,并将在我的回答中添加一些内容 如果您关心迭代顺序,请使用表示您关心迭代顺序的方法。【参考方案3】:

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

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

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

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

【讨论】:

以上是关于Stream.sorted().forEach() 是不是按预期工作? [复制]的主要内容,如果未能解决你的问题,请参考以下文章

JDK8 集合排序 xxxList.stream.sorted(...)

JDK8 集合排序 xxxList.stream.sorted(...)

JDK 8 之 Stream sorted() 示例

java8 stream sorted

java8 .stream().sorted().filter().map().collect()用法

Stream流的排序用法