在java源代码中,Collectors.toList定义为
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);
}
我们将BinaryOperator视为CollectorImpl的第三个参数,它在线性时间内合并两个子结果。 这是否意味着,如果通过Stream.collect方法频繁使用此函数,我们可以获得平方计算时间?
考虑以下代码:
List<Integer> desc = Stream.iterate(n, k -> k - 1).limit(n + 1)
.collect(Collectors.toList());
desc.parallelStream()
.map(k -> {
try {
Thread.sleep(k * 500);
} catch (InterruptedException ignored) {
}
return k;
})
.collect(Collectors.toList());
第二个流的元素恰好按降序计算。收集方法最简单的方法是将每个数字包装到List中并将所有下一个数字添加到其中,总共有方形复杂度,多么悲伤。
答案 0 :(得分:2)
在这种情况下,输入desc
列表将根据系统所具有的硬件线程数划分为多个独立部分。通常它在4核系统上有16个部分(尽管它没有指定并且可能会改变)。每个部分将使用累加器独立处理,然后使用组合器将结果合并在一起。因此它不会降低到二次复杂度,但是,许多不必要的复制将会完成。
实际上使用toArray()
方法效率更高。它检查流源特性,在您的情况下,它特别优化,因为源是SIZED和SUBSIZED,因此结果可以写入单个数组而无需任何额外的复制。如果您需要List
,可以考虑使用Arrays.asList(desc.parallelStream()....toArray(Integer[]::new))