Answers:
您在问错问题。您正在询问sequential
vs. parallel
而要按顺序处理项目,因此您必须询问订购。如果您有一个有序的流并执行保证维持顺序的操作,则该流是并行还是顺序处理都无关紧要;实施将维持秩序。
有序属性不同于并行与顺序。例如,如果你调用stream()
一个HashSet
同时调用流将是无序stream()
在List
返回的有序流。请注意,您可以致电unordered()
以解除订购合同并可能提高性能。一旦流没有排序,就无法重新建立排序。(将无序流转换为有序流的唯一方法是调用sorted
,但是生成的顺序不一定是原始顺序)。
又见“订购”一节中的java.util.stream
包文档。
为了确保在整个流操作中维持顺序,您必须研究流源,所有中间操作和终端操作的文档,以了解它们是否维持顺序(或源是否在第一个顺序中具有顺序)地点)。
这可能非常微妙,例如,Stream.iterate(T,UnaryOperator)
创建有序流而Stream.generate(Supplier)
创建无序流。请注意,由于没有保持顺序,您在问题中也犯了一个常见错误。如果要以保证的顺序处理流的元素,则必须使用。forEach
forEachOrdered
因此,如果您list
的问题确实是java.util.List
,则其stream()
方法将返回有序流,并且filter
不会更改顺序。因此,如果调用list.stream().filter() .forEachOrdered()
,则将按顺序顺序处理所有元素,而对于list.parallelStream().filter().forEachOrdered()
元素,则可能会并行处理(例如,通过过滤器),但仍将按顺序调用终端操作(显然,这将减少并行执行的好处) 。
例如,如果您使用类似
List<…> result=inputList.parallelStream().map(…).filter(…).collect(Collectors.toList());
整个操作可能会受益于并行执行,但是无论您使用并行流还是顺序流,结果列表始终会以正确的顺序排列。
List<>
会保留订单,但会Collection<>
吗?
forEachOrdered
仅与forEach
使用并行流不同-但在良好的实践中,如果订购方法发生变化,无论如何在订购时都应使用它...
排序取决于源数据结构和中间流操作。假设您正在使用,List
则应该对处理进行排序(因为filter
此处不会更改顺序)。
S sequential()
Returns an equivalent stream that is sequential. May return itself, either because the stream was already sequential, or because the underlying stream state was modified to be sequential.
This is an intermediate operation.
S parallel()
Returns an equivalent stream that is parallel. May return itself, either because the stream was already parallel, or because the underlying stream state was modified to be parallel.
This is an intermediate operation.
S unordered()
Returns an equivalent stream that is unordered. May return itself, either because the stream was already unordered, or because the underlying stream state was modified to be unordered.
This is an intermediate operation.
流可能具有也可能没有定义的遇到顺序。流是否具有遇到顺序取决于源和中间操作。某些流源(例如List或数组)在本质上是有序的,而其他流源(例如HashSet)则不是。某些中间操作(例如sorted())可能会在其他情况下将无顺序流强加一个遇到顺序,而其他一些操作可能会使有序流(例如BaseStream.unordered())变得无序。此外,某些终端操作可能会忽略遇到顺序,例如forEach()。
如果对流进行了排序,则大多数操作将被约束为按其遇到顺序对元素进行操作;如果流的源是包含[1、2、3]的列表,则执行map(x-> x * 2)的结果必须为[2、4、6]。但是,如果源没有定义的遇到顺序,则值[2、4、6]的任何排列都是有效的结果。
对于顺序流,是否存在相遇顺序不会影响性能,只会影响确定性。如果订购了一个流,则在相同的源上重复执行相同的流管道将产生相同的结果;如果未订购,重复执行可能会产生不同的结果。
对于并行流,放宽排序约束有时可以使执行效率更高。如果元素的顺序无关紧要,则可以更有效地实现某些聚合操作,例如过滤重复项(distinct())或分组的约简(Collectors.groupingBy())。同样,本质上与遇到顺序相关的操作(例如limit())可能需要缓冲以确保正确的顺序,从而削弱了并行性的优势。如果流具有遇到顺序,但用户并不特别关心该遇到顺序,则使用unordered()对流进行明确排序可以提高某些状态操作或终端操作的并行性能。但是,大多数流管道,例如上面的“块权重之和”示例,