通常,这两段代码之间在性能上有区别吗?
List<Integer> list1 = someStream1.sorted().collect(toList());
// vs.
List<Integer> list2 = someStream2.collect(toList());
list2.sort(Comparator.naturalOrder())
变体2显然令人讨厌,应该避免,但是我很好奇Stream的主流(heh,main stream )实现中是否内置了任何性能优化功能两者之间的差异。
我认为,由于流中严格包含有关情况的更多信息,因此它将有更好的机会进行优化。例如。我想如果这有一个findFirst()
调用,它将取消排序,而支持min
操作。
答案 0 :(得分:4)
两个选项的最终结果应该相同。但是运行时特征可以不同。如果初始流是并行流,该怎么办?然后,选项1会并行进行排序,而选项2则不会进行“顺序”排序。结果应该相同,但整体运行时响应。然后,CPU负载可能会大不相同。
相对于2,我绝对更喜欢选项1:为什么先创建列表,然后再进行 排序?
例如,假设您以后想收集到不可变列表中。然后,遵循第二种模式的所有代码都会中断。而使用模式1编写的代码完全不会受到影响!
当然,在这里的示例中不应引起问题,但是如果sort()发生在稍微不同的地方怎么办?!
答案 1 :(得分:3)
从概念上讲,流通常被视为正在处理/操纵的“瞬态”数据,收集流可以传达您已经完成操纵的概念。
第二个代码段应该起作用,而第一个代码段是更惯用的处理方式。
答案 2 :(得分:3)
在第一种情况下,排序发生在对collect
的调用中。如果流已经排序,则将是无操作(数据将按原样传递)。可能没什么大不同,但是在已经排序的集合上调用Collections.sort
仍然是O(n)。
第一种情况也受益于并行执行,因为至少OpenJDK使用Arrays.parallelSort
。
除了第一行更清晰外,更好地理解并且在重构时较少出错。
答案 3 :(得分:1)
从Collectors.toList()
返回的列表不保证是可编辑的。 可能是一个ArrayList或ImmutableList,您可能不知道。因此,您不得尝试修改该列表。
答案 4 :(得分:0)
根据文档,对于无序流,第一排序似乎不是稳定的排序实现:
对于有序流,排序是稳定的。对于无序流,无法保证稳定性。
但是第二个是稳定的排序实现:
此实现是一种稳定的,自适应的迭代合并排序,在对输入数组进行部分排序时,所需的比较少于n lg(n),而在对输入数组进行随机排序时,它提供了传统合并排序的性能。如果输入数组几乎已排序,则该实现需要大约n个比较。
因此,排序算法的稳定性是这两个列表排序方法之间的差异之一。