.collect是否保证在并行流上排序?

J_F*_*B_M 51 java list java-8

鉴于我有一个字符串列表List<String> toProcess.结果必须按原始线的顺序排列.我想利用新的并行流.

以下代码是否保证结果与原始列表中的顺序相同?

// ["a", "b", "c"]
List<String> toProcess;

// should be ["a", "b", "c"]
List<String> results = toProcess.parallelStream()
                                .map(s -> s)
                                .collect(Collectors.toList());
Run Code Online (Sandbox Code Playgroud)

Joh*_*ica 52

TL; DR

是的,订单是有保证的.

Stream.collect()API文档

起点是看什么决定减少是否并发.Stream.collect()的描述如下:

如果流是并行的,并且Collector并发的,并且流是无序的或收集器是无序的,那么将执行并发减少(Collector有关并发减少的详细信息,请参阅.)

满足第一个条件:流是并行的.第二个和第三个怎么样:Collector并发和无序?
 

Collectors.toList()API文档

toList()的文件是:

返回一个Collector将输入元素累积为new的元素List.返回的类型,可变性,可序列性或线程安全性无法保证List; 如果List需要对返回的更多控制,请使用toCollection(Supplier).

返回:
一个收集器,它按照遭遇顺序将所有输入元素收集到List

遭遇顺序工作的操作按原始顺序对元素进行操作.这取代了并行性.
 

实施代码

检查实施Collectors.java确认toList()没有包含CONCURRENTUNORDERED特征.

public static <T>
Collector<T, ?, List<T>> toList() {
    return new CollectorImpl<>((Supplier<List<T>>) ArrayList::new, List::add,
                               (left, right) -> { left.addAll(right); return left; },
                               CH_ID);
}

// ...

static final Set<Collector.Characteristics> CH_ID
        = Collections.unmodifiableSet(EnumSet.of(Collector.Characteristics.IDENTITY_FINISH));
Run Code Online (Sandbox Code Playgroud)

注意收集器如何具有CH_ID特征集,该特征集仅具有单个IDENTITY_FINISH特征.CONCURRENT并且UNORDERED不存在,因此减少不能同时进行.

非并发减少意味着,如果流是并行的,则集合可以并行进行,但是它将被分成几个线程限制的中间结果,然后将其组合.这确保了组合结果处于遭遇顺序.
 

另请参阅: 为什么在Java 8中按顺序收集并行流


Mis*_*sha 6

您可以保证获得遇到订单的元素.

来自以下文件toList:

返回:一个收集器,它按照遭遇顺序将所有输入元素收集到List

有关术语"遇到订单"的更多信息,请参阅java.util.streams摘要.

此外,List#spliterator文档要求List生成分裂器的所有实现是ORDERED:

Spliterator报告Spliterator.SIZED和Spliterator.ORDERED.实施应记录其他特征值的报告.

奇怪的是,虽然List界面需要iterator()以"正确的顺序"生成元素,但只需要按顺序spliterator()排序,但不需要特别要求遵循列表的自然顺序.

因此,为了回答你的问题,所产生的列表toList保证包含与源列表的分裂器命令它们完全相同的元素.流是并行还是顺序无关紧要.