Understanding Collections.sort() in Java

Jhanak Didwania
Analytics Vidhya
Published in
3 min readDec 7, 2020

As the name suggests, the Collections class of java provides a static method called sort() which is used to sort a collection of items in a particular order.

public static <T> void sort(List<T> list, Comparator<? super T> c) {
list.sort(c);
}

Let’s look at the definition of this method. As we can see, it takes two arguments, one is the List of objects of type T and other is a Comparator which accepts objects of type T and return an order in which list sorting has to be done. In this function definition, we are giving a Comparator to define a sorting order explicitly.

There is one more definition for Collections.sort() method.

public static <T extends Comparable<? super T>> void sort(List<T> list) {
list.sort((Comparator)null);
}

In this definition, static sort method only accepts the List of objects of type T and it sorts them in a default order. Here we can see that, to sort T in some default order, T must implement the Comparable interface.

It is important to note that,

All wrapper classes and String class implement Comparable interface in Java. Wrapper classes are compared by their values, and strings are compared lexicographically. By default, they sort the elements in the ascending order.

To sort the remaining objects of type, T, using Collections.sort() method, either:

  1. The object should implement the Comparable interface, or,
  2. We should define a custom Comparator that can sort the objects of type T and pass it into our sort function as the second argument.

Comparable interface

Taking an example of Integer wrapper class. Integer class implements Comparable interface. Comparable interface has a method called as compareTo(). Inside the Integer class, it overrides the compareTo method. It compares the current object with the object being passed in the sort function, let’s call it var1 and it returns -1,0,1 when the current object is less than var1, when current object equals to var1 and when current object is greater than var1, respectively.

Comparable Interface:
public interface
Comparable<T> {
int compareTo(T var1);
}
____________________________________________________________________
Integer class:
public int
compareTo(Integer anotherInteger) {
return compare(this.value, anotherInteger.value);
}

public static int compare(int x, int y) {
return x < y ? -1 : (x == y ? 0 : 1);
}

So, it means whenever a class implements the Comparable interface, it can add it’s own logic in compareTo function and hence can have it’s own logic for sorting.

Now, what if we want to sort the objects of type T in some other order that is different from the default ordering. To solve this, Comparator comes into picture.

Comparator interface

When we want to define an ordering for sorting the objects of some type T, we can create a custom Comparator, which we can pass in our Collections.sort() method as the second argument while sorting List<T> list.

@FunctionalInterface
public interface Comparator<T> {
int compare(T var1, T var2);
...
}

Comparator is a functional interface.
A functional interface in Java is an interface that contains only a single abstract (unimplemented) method. A functional interface can contain default and static methods which do have an implementation, in addition to the single unimplemented method.

Comparator interface has a single abstract method known as compare(). It compares the two objects T1 and T2 and generally returns -1, 0, 1 when T1<T2, when T1==T2 and when T1>T2, respectively in most of the implementations.

Example illustrating the use of Comparator interface while sorting the objects of type T in ascending order.

Suppose Object T has following two attributes: dataLimit, dataUsed both of type integer.

Defining the Comparator inside the function argument

Collections.sort(list, new Comparator<T>() {
//Sort based on ascending order of dataLimit
@Override
public int compare(T obj1, T obj2) {
return obj1.getDataLimit()-obj2.getDataLimit();
}
});

Defining the Comparator outside and passing it’s object in function’s argument

Comparator<T> CustomComparator= new Comparator<T>() {
@Override
public int compare(T o1, T o2) {
return o1.getDataLimit()-o2.getDataLimit();
}
};
Collections.sort(list, CustomComparator);

Using lambda expression with Constructor

list.sort((T o1, T o2) -> o1.getDataLimit()-o2.getDataLimit());orComparator<T> CustomComparator = (o1, o2)-> o1.getDataLimit()-o2.getDataLimit();
list.sort(CustomComparator);

To sort in descending order: This function reversed() can used with any Comparator by function chaining to change the sorting logic to reverse order.

default Comparator<T> reversed() {
return Collections.reverseOrder(this);
}
Comparator<T> CustomComparator = (o1, o2)-> o1.getDataLimit()-o2.getDataLimit();
list.sort(CustomComparator.reversed());

You can explore more methods of comparable and Comparator interface and understand it’s working by digging deep into the wrapper classes.

Guys I really hope that you find this article valuable! If still you have any queries, you can surely discuss them in the comment section below.

Thanks a lot for devoting your time to this blog.

Please share it among your colleagues and clap for showing appreciation! :)

--

--