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

Pankaj :

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?

NoDataFound :

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>

Guess you like

Origin http://43.154.161.224:23101/article/api/json?id=143194&siteId=1