源的无序性质或通过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,包括 cmets。
所以
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 特性的评估是在执行开始之前通过源、中间操作和终端操作的特性完成的吗?”的答案是,是的,这是在开始实际处理之前通过为流水线阶段选择适当的算法来完成的,如果有选择的话,但是这个过程不一定会导致整个流水线的单一特征。