在Java流中遇到订单保留
问题内容:
我经历了相关的问题,例如如何确保java8流中的处理顺序?,输出元件的排序对我来说还不是很清楚。因此,请澄清我的以下疑问。
Integer[] intArray = {1, 2, 3, 4, 5, 6, 7, 8 };
List<Integer> listOfIntegers =
new ArrayList<>(Arrays.asList(intArray));
listOfIntegers
.parallelStream()
.unordered()
.forEachOrdered(e -> System.out.print(e + " "));
我认为至少从理论上(或根据Java规范),它可以比1、2、3、4、5、6、7、8随机打印。我正确吗?
另一个相关的问题-遇到顺序保存的决定是在执行的哪一点进行的?更准确地说-
甚至在执行开始之前,是否通过查看源,中间操作和终端操作的特性来完成整个流管道ORDER特性的评估?
问题答案:
货源的无序性质或订单合同的显式释放unordered()
可能会影响所有后续的流水线阶段,除非它们引入只能在sorted
操作中发生的订单。
对于无状态中间操作(例如filter
和)map
,没有任何区别,但是操作skip
(limit
和)distinct
可能会根据先前的流状态是有序还是无序而表现出不同的行为。此答案显示了一个示例如何distinct
受先前事件影响的示例unordered()
。
请注意,原则上,sorted
在引入顺序时,可能取决于前一阶段的有序状态,因为如果前一流是无序的,则它可能使用不稳定的排序算法。
该答案提供了一种打印流的特性并评估它们由于附加其他操作而如何变化的方法。
链接终端操作时,终端操作本身的无序性质或终端操作之前最后阶段的无序状态都可能足以为终端操作选择不尝试保留顺序的算法。
原则上,终端操作的无序性质可以用来影响之前的阶段,但因为无状态的中间操作不会反正影响和skip
,limit
,distinct
必须遵守先前的有序状态,如果存在的话,可能受到影响的唯一操作,是sorted
如果后续操作无论如何都不在乎订单,则这变得过时了。
在当前的实现中,自Java
8更新60起,终端操作的无序性质不会影响先前阶段的行为。与以前的实现方式一样,进行了此更改,并且错误地影响了skip
和limit
。放任放弃过时的分类步骤的机会不被认为是问题,因为sort
与无序的后续操作进行链接是一个极端的情况。如果您想进一步了解相关讨论,请参阅此答案,包括评论。
因此对于
list.stream() // List.stream() returns an ordered stream
.unordered() // releases order contract
.distinct() // for equal elements, it may pick an arbitrary one
.sorted() // re-introduces an order
.skip(1) // will skip the minimum element due to the order
.forEach(System.out::println); // may print the remaining elements in arbitrary order
流管道没有单一的有序或无序行为。
与…相比
hashSet.stream() // HashSet.stream() has no order (unless being a LinkedHashSet)
.filter(Objects::nonNull) // not affected by order
.distinct() // may use unorderedness, but has no effect anyway, as already distinct
.skip(1) // may skip an arbitrary element
.forEachOrdered(System.out::println); // would respect order if there was one
整个管道无序运行,只是因为源无序。如果订购了货源,则将完全订购。
因此,“答案是否 是在执行开始之前就通过遍历源,中间操作和终端操作的特性来完成对整个流水线ORDER特性的评估?
”是的,是的,这是在开始实际处理之前,通过为流水线阶段选择适当的算法来完成的,但有选择的话,但是此过程不一定会导致整个流水线具有单个特征。