我已经完成了How to ensure order of processing in java8 streams?之类的相关问题,但仍然没有完全清楚输出元素的排序。因此,请澄清我的疑问。
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特性?
答案 0 :(得分:4)
源的无序性或通过unordered()
明确释放订单合同可能会影响所有后续流水线阶段,除非它们引入的订单只能在sorted
操作时发生。
对于filter
和map
等无状态中间操作,无论如何都没有区别,但skip
,limit
和distinct
等操作可能会有所不同行为取决于先前的流状态是有序还是无序。 This answer显示了distinct
如何影响unordered()
的示例。
请注意,原则上,sorted
在引入订单时可能取决于前一阶段的有序状态,因为如果前一个流是无序的,它可能会使用不稳定的排序算法。
This answer提供了一种打印流特征的方法,并评估了由于附加其他操作而导致的更改方式。
当您链接终端操作时,终端操作本身的无序性质或终端操作之前的最后一级的无序状态可能足以为不尝试保留的终端操作选择算法订单。
原则上,终端操作的无序性可用于影响前一阶段,但由于无状态中间操作无论如何都不受影响,skip
,limit
,distinct
必须服从以前的有序状态(如果存在),唯一可能受影响的操作是sorted
,如果后续操作无论如何都不关心该命令就会过时。
在当前实现中,由于Java 8更新60,终端操作的无序性质不影响先前阶段的行为。与以前的实施方案一样,此更改已对skip
和limit
产生了错误的影响。没有机会消除过时的排序步骤并不是一个问题,因为将sort
与无序的后续操作联系起来是一个极端的案例。如果您想了解有关相关讨论的更多信息,请参阅this answer,包括评论。
所以
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特性,通过执行源,中间操作和终端操作的特性,甚至在开始执行之前完成?”是,是的,这是在开始实际处理之前完成的,通过为有选择的流水线阶段选择适当的算法,但是这个过程不一定会导致整个管道的单个特征。
答案 1 :(得分:2)
一旦您选择unordered
,最终结果就可以以基本上随机的顺序通过。请注意,虽然没有要求它,但实际上您可能仍会在输出中看到一些排序。
forEachOrdered
会保留“流”的遭遇顺序,因此,如果您没有.unordered()
,那么它会确保您看到遇到顺序的元素。如果该流已经unordered
,那么它就毫无意义,您也可以使用forEach
。
换句话说,forEachOrdered
会在已排序的流中保留遭遇顺序。它不会进行任何排序或其他排序,但如果流已经unordered
,那么任何事情都可能发生。