列表接口排序方法和流接口排序方法有什么区别?

时间:2019-05-05 10:43:52

标签: java list sorting java-8 java-stream

我对根据对象中的日期属性对对象列表进行排序感兴趣。我可以使用列表排序方法。

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());

在上述两个选项中,我们应该使用以及为什么?

我知道前者将更新我的原始列表,而后者将不更新原始列表,而是给我一个新的新列表对象。

所以,我不在乎我的原始列表是否正在更新。那么哪一个是好的选择,为什么呢?

5 个答案:

答案 0 :(得分:2)

如果您只需要对List进行排序,并且不需要任何其他流操作(例如过滤,映射等),那么增加创建{{ 1}},然后创建一个新的Stream。仅对原始List进行排序会更有效。

答案 1 :(得分:1)

流有一些开销,因为它会创建许多新对象,例如具体的StreamCollector和新的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 )。
    • 如果排序后进行了map转换,并且您松开了使用原始键进行排序的方法。

如果将流与其他中间操作一起使用,则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()。

如果您所做的只是简单的过滤,则还可以使用TreeSetcollectingAndThen操作:

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()));

它比第二个要快得多,并且没有创建新的中间对象。如果您要执行其他一些流操作(例如过滤,映射),则可以使用第二种方法。