Pankaj
Pankaj

Reputation: 61

What's the difference between list interface sort method and stream interface sorted method?

I'm interested in sorting an list of object based on date attribute in that object. I can either use list sort method.

list.sort( (a, b) -> a.getDate().compareTo(b.getDate()) );

Or I can use stream sorted method

List<E> l = list.stream()
                .sorted( (a, b) -> a.getDate().compareTo(b.getDate()))
                .collect(Collectors.toList());

Out of both above option which should we use and why?

I know the former one will update my original list and later one will not update the original but instead give me a fresh new list object.

So, I don't care my original list is getting updated or not. So which one is good option and why?

Upvotes: 2

Views: 1002

Answers (5)

NoDataFound
NoDataFound

Reputation: 11959

If you wish to known which is best, your best option is to benchmark it: you may reuse my answer JMH test.

It should be noted that:

  • List::sort use Arrays::sort. It create an array before sorting. It does not exists for other Collection.
  • Stream::sorted is done as state full intermediate operation. This means the Stream need to remember its state.

Without benchmarking, I'd say that:

  • You should use collection.sort(). It is easier to read: collection.stream().sorted().collect(toList()) is way to long to read and unless you format your code well, you might have an headache (I exaggerate) before understanding that this line is simply sorting.
  • sort() on a Stream should be called:
    • if you filter many elements making the Stream effectively smaller in size than the collection (sorting N items then filtering N items is not the same than filtering N items then sorting K items with K <= N).
    • if you have a map transformation after the sort and you loose a way to sort using the original key.

If you use your stream with other intermediate operation, then sort might be required / useful:

collection.stream()    // Stream<U> #0
          .filter(...) // Stream<U> #1
          .sorted()      // Stream<U> #2
          .map(...)    // Stream<V> #3
          .collect(toList()) // List<V> sorted by U.
          ;

In that example, the filter apply before the sort: the stream #1 is smaller than #0, so the cost of sorting with stream might be less than Collections.sort().

If all that you do is simply filtering, you may also use a TreeSet or a collectingAndThen operation:

collection.stream()    // Stream<U> #0
          .filter(...) // Stream<U> #1
          .collect(toCollection(TreeSet::new))
          ;

Or:

collection.stream() // Stream<U>
          .filter(...) // Stream<U>
          .collect(collectingAndThen(toList(), list -> {
            list.sort(); 
            return list;
          })); // List<V>

Upvotes: 1

Sweeper
Sweeper

Reputation: 272665

Streams have some overheads because it creates many new objects like a concrete Stream, a Collector, and a new List. So if you just want to sort a list and doesn't care about whether the original gets changed or not, use List.sort.

There is also Collections.sort, which is an older API. The difference between it and List.sort can be found here.

Stream.sorted is useful when you are doing other stream operations alongside sorting.

Your code can also be rewritten with Comparator:

list.sort(Comparator.comparing(YourClass::getDate)));

Upvotes: 1

Lungu Daniel
Lungu Daniel

Reputation: 844

You use the first method

list.sort((a, b) -> a.getDate().compareTo(b.getDate()));

it's much faster than the second one and it didn't create a new intermediate object. You could use the second method when you want to do some additional stream operations (e.g. filtering, map).

Upvotes: 0

Paragoumba
Paragoumba

Reputation: 88

First one would be better in term of performance. In the first one, the sort method just compares the elements of the list and orders them. The second one will create a stream from your list, sort it and create a new list from that stream.

In your case, since you can update the first list, the first approach is the better, both in term of performance and memory consumption. The second one is convenient if you need to and with a stream, or if you have a stream and want to end up with a sorted list.

Upvotes: 0

Eran
Eran

Reputation: 393916

If you only need to sort your List, and don't need any other stream operations (such as filtering, mapping, etc...), there's no point in adding the overhead of creating a Stream and then creating a new List. It would be more efficient to just sort the original List.

Upvotes: 2

Related Questions