如何确保 java8 流中的处理顺序?

2022-01-22 00:00:00 java-8 java java-stream

我想处理 XML java 对象中的列表.我必须确保按照收到的顺序处理所有元素.

I want to process lists inside an XML java object. I have to ensure processing all elements in order I received them.

因此,我应该在我使用的每个 stream 上调用 sequential 吗?list.stream().sequential().filter().forEach()

Should I therefore call sequential on each stream I use? list.stream().sequential().filter().forEach()

或者只要我不使用并行性,只使用流就足够了吗?list.stream().filter().forEach()

Or it it sufficient to just use the stream as long as I don't use parallelism? list.stream().filter().forEach()

推荐答案

你问错问题了.您正在询问 sequentialparallel 而您想按顺序处理项目,因此您必须询问 ordering.如果你有一个 ordered 流并执行保证保持顺序的操作,那么流是并行处理还是顺序处理都没有关系;实现将保持顺序.

You are asking the wrong question. You are asking about sequential vs. parallel whereas you want to process items in order, so you have to ask about ordering. If you have an ordered stream and perform operations which guarantee to maintain the order, it doesn’t matter whether the stream is processed in parallel or sequential; the implementation will maintain the order.

有序属性不同于并行与顺序.例如.如果您在 HashSet 上调用 stream(),则在 List 上调用 stream() 时,流将是无序的返回一个有序流.请注意,您可以调用 unordered() 释放排序合约并潜在地提高性能.一旦流没有排序,就无法重新建立排序.(将无序流转为有序流的唯一方法是调用sorted,但是得到的顺序不一定是原始顺序.

The ordered property is distinct from parallel vs sequential. E.g. if you call stream() on a HashSet the stream will be unordered while calling stream() on a List returns an ordered stream. Note that you can call unordered() to release the ordering contract and potentially increase performance. Once the stream has no ordering there is no way to reestablish the ordering. (The only way to turn an unordered stream into an ordered is to call sorted, however, the resulting order is not necessarily the original order).

另请参阅 ">java.util.stream 包文档.

See also the "Ordering" section of the java.util.stream package documentation.

为了确保在整个流操作中保持顺序,您必须研究流的源,所有中间操作和终端操作的文档,以了解它们是否保持顺序(或源是否有顺序)首先).

In order to ensure maintenance of ordering throughout an entire stream operation, you have to study the documentation of the stream’s source, all intermediate operations and the terminal operation for whether they maintain the order or not (or whether the source has an ordering in the first place).

这可能非常微妙,例如Stream.iterate(T,UnaryOperator) 创建有序流,而 Stream.generate(Supplier) 创建一个无序 流.请注意,您在问题中也犯了一个常见错误,即 forEach 不保持顺序.您必须使用 forEachOrdered 如果您想以保证的顺序处理流的元素.

This can be very subtle, e.g. Stream.iterate(T,UnaryOperator) creates an ordered stream while Stream.generate(Supplier) creates an unordered stream. Note that you also made a common mistake in your question as forEach does not maintain the ordering. You have to use forEachOrdered if you want to process the stream’s elements in a guaranteed order.

因此,如果您的问题中的 list 确实是 java.util.List,则其 stream() 方法将返回一个 ordered 流和 filter 不会改变排序.所以如果你调用 list.stream().filter() .forEachOrdered(),所有的元素都会按顺序依次处理,而对于 list.parallelStream().filter().forEachOrdered() 元素可能会被并行处理(例如通过过滤器),但终端操作仍将按顺序调用(这显然会降低并行执行的好处).

So if your list in your question is indeed a java.util.List, its stream() method will return an ordered stream and filter will not change the ordering. So if you call list.stream().filter() .forEachOrdered(), all elements will be processed sequentially in order, whereas for list.parallelStream().filter().forEachOrdered() the elements might be processed in parallel (e.g. by the filter) but the terminal action will still be called in order (which obviously will reduce the benefit of parallel execution).

例如,如果您使用类似的操作

If you, for example, use an operation like

List<…> result=inputList.parallelStream().map(…).filter(…).collect(Collectors.toList());

整个操作可能会从并行执行中受益,但无论您使用并行流还是顺序流,结果列表都将始终按正确的顺序排列.

the entire operation might benefit from parallel execution but the resulting list will always be in the right order, regardless of whether you use a parallel or sequential stream.

相关文章