Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Why can Collections.sort take no comparator but List.sort must take a comparator?

I don't understand the logic why List.sort() doesn't have a version with no comparator.

Specially I see it's possible to call List.sort with null:
list.sort(null), and it seems it uses the natural order for sorting.

I noticed in my IDE Collections.sort() calls List.sort(null), so I was wondering why List.sort which seems to be more recently introduced in Java 8 doesn't have a simple version with no comparator, which in many cases is not needed.

Also I am not sure in this situation whether it's better to call List.sort(null) to avoid an extra call, or if it's still preferred to call Collections.sort() and avoid the ugly null argument.

like image 300
apadana Avatar asked Apr 15 '20 06:04

apadana


People also ask

Does collections sort use Comparator?

We can also sort the student names in descending order using Collections. reverseOrder(). Output: Sorting in descending order can be done using a comparator too.

How does sort work with Comparator?

Whenever we need to sort the values in a collection, this “sort” method transfers control to the compare method in the class. The compare method then returns some values based on the comparison. It returns 0 if both the objects are equal. This returns 1 if the first object is greater than the second.

What does Collection sort () do?

sort. Sorts the specified list into ascending order, according to the natural ordering of its elements. All elements in the list must implement the Comparable interface.


1 Answers

tldr

It is a design decision, mixed with some historical reasons. It would be possible to add a list.sort() but it could not ensure safety at compile-time, only runtime. Which would be a rather weird and unusual design for the JDK.


Collections#sort

Collections, because it can specify type bounds in the method declaration, has the possibility to force Comparable elements:

public static <T extends Comparable<? super T>> void sort(List<T> list)

So the method can ensure that the collection contains Comparable elements. So a Comparator is not needed.


List#sort

List can not do that. Its generic type must allow everything, You have to be able to use a List<Dog> although those are maybe not Comparable.

So if there would be a list.sort(), then this method would need to figure out whether the lists generic type T is Comparable or not. But that information is only present on runtime, we want it at compile-time for a nice design though.

Because this would lead to a bad design, list.sort() does not exist. Hence the extra method forcing a Comparator which can ensure safety at compile-time..


list.sort(null)

Having list.sort(null) instead of list.sort() is clearly a design choice, a good one in my opinion. As said before, it is not possible for List to ensure safety at compile-time. So the only choice is to go for runtime safety, which is not as good.

Having a list.sort() that only sometimes works and throws an exception otherwise would be a weird design choice. A call like list.sort(null) however is much clearer to any user. Especially, it is clearer that this will be covered by runtime decisions, not by compile-time checks.

You might want to prefer to make it explicit and give it the trivial Comparator that uses the natural ordering:

list.sort(Comparator.naturalOrder());

That would at least be even clearer to a reader.


History

You might wonder now why List.sort(null) even is a supported feature and why they do not require you to give it an explicit Comparator always. I can not look into the developers mind but I suspect historical reasons. There are quite a few similar examples in the JDK, especially with sorting.

This is mainly because Java maintains backwards compatibility. Generics were introduced with Java 5, so everything that existed before which was dealing with containers was not designed with type safety in mind.

There are a couple of highly related examples:

  • Arrays#sort(Object[]) (since Java 1.2) does not force Comparable. Therefore, they had to add an extra overload in Java 5 Arrays.sort(T[], Comparator), exactly like the List example.
  • The method Collections.sort(T[], Comparator) actually accepts null for the comparator. A bad design choice, but it was made back then when generics did not exist yet. So they could not remove this feature anymore.
  • Interestingly they made the decision to let List.sort(Comparator), a new method, also support null. However, in Stream.sort(Comparator) they did not. This is a weird inconsistency in the JDK.
like image 91
Zabuzard Avatar answered Sep 19 '22 14:09

Zabuzard