我对根据对象中的日期属性对对象列表进行排序感兴趣。我可以使用列表排序方法。
list.sort( (a, b) -> a.getDate().compareTo(b.getDate()) );
或者我可以使用流排序方法
List<E> l = list.stream()
.sorted( (a, b) -> a.getDate().compareTo(b.getDate()))
.collect(Collectors.toList());
在上述两个选项中,我们应该使用以及为什么?
我知道前者将更新我的原始列表,而后者将不更新原始列表,而是给我一个新的新列表对象。
所以,我不在乎我的原始列表是否正在更新。那么哪一个是好的选择,为什么呢?
答案 0 :(得分:2)
如果您只需要对List
进行排序,并且不需要任何其他流操作(例如过滤,映射等),那么增加创建{{ 1}},然后创建一个新的Stream
。仅对原始List
进行排序会更有效。
答案 1 :(得分:1)
流有一些开销,因为它会创建许多新对象,例如具体的Stream
,Collector
和新的List
。因此,如果您只想对列表进行排序,而不关心原始文档是否被更改,请使用List.sort
。
还有Collections.sort
,它是一个较旧的API。它与List.sort
之间的区别可以在here中找到。
Stream.sorted
在进行排序以外的其他流操作时很有用。
您的代码也可以用Comparator
重写:
list.sort(Comparator.comparing(YourClass::getDate)));
答案 2 :(得分:1)
如果您想知道哪种最好,最好的选择是对其进行基准测试:您可以重用我的answer JMH test。
应注意:
List::sort
使用Arrays::sort
。它在排序之前创建一个数组。其他Collection
不存在。Stream::sorted
作为状态完全中间操作完成。这意味着Stream
需要记住其状态。如果没有基准测试,我会这样说:
collection.sort()
。更容易阅读:collection.stream().sorted().collect(toList())
是一种很长的阅读方法,除非您对代码进行正确的格式化,否则在理解该行仅是排序之前,您可能会头疼(我夸大了)。sort()
上的Stream
应该被称为:
Stream
的大小实际上小于集合(先排序N个项目,然后过滤N个项目,则不同于先过滤N个项目,然后进行排序K个项目,其中K <= N )。如果将流与其他中间操作一起使用,则sort
可能是必需的/有用的:
collection.stream() // Stream<U> #0
.filter(...) // Stream<U> #1
.sorted() // Stream<U> #2
.map(...) // Stream<V> #3
.collect(toList()) // List<V> sorted by U.
;
在该示例中,过滤器在排序之前应用:流#1小于#0,因此使用流进行排序的成本可能小于Collections.sort()。
如果您所做的只是简单的过滤,则还可以使用TreeSet
或collectingAndThen
操作:
collection.stream() // Stream<U> #0
.filter(...) // Stream<U> #1
.collect(toCollection(TreeSet::new))
;
或者:
collection.stream() // Stream<U>
.filter(...) // Stream<U>
.collect(collectingAndThen(toList(), list -> {
list.sort();
return list;
})); // List<V>
答案 3 :(得分:0)
第一个在性能方面会更好。在第一个中,sort方法只是比较列表中的元素并对其进行排序。第二个将从您的列表中创建一个流,对其进行排序,然后从该流中创建一个新列表。
在您的情况下,由于可以更新第一个列表,因此从性能和内存消耗两方面来看,第一种方法更好。如果需要并带有流,或者如果有流并且想要以排序后的列表结尾,则第二个方便。
答案 4 :(得分:0)
您使用第一种方法
list.sort((a, b) -> a.getDate().compareTo(b.getDate()));
它比第二个要快得多,并且没有创建新的中间对象。如果您要执行其他一些流操作(例如过滤,映射),则可以使用第二种方法。