Sort list of objects
Suppose you have a list which contains objects of your own class rather than java’s built in classes such as java.lang.Integer
, java.lang.String
etc.
Now you want this list of objects to be sorted by field of this class.
Let’s say we have a User class which contains user details such as name, age, address etc., and we have a list of different users.
We want a list wherein users are listed in the order of their increasing age. That is, we need to sort the above list by a field named age.
In this article, we will understand how to do this using Collections.sort()
method in java.
Collections.sort()
You can sort a list using sort()
method of java.util.Collections
class.
sort()
is a static
method and can be invoked as Collections.sort()
.
sort()
accepts a list of objects to be sorted.
If the list is of built in java types such as String
, Integer
etc., sort()
will sort it in ascending order by default.
But if you pass a list of custom objects to this method, how does this method know the criteria to sort the list or the field of objects by which it should sort.
That is, whether it should sort on name, age or some other field.
Thus, we need some way to inform sort()
method about the field on which it should sort the list.
There are two overloaded versions of sort()
method in Collections
. Their signatures are
1. sort(List<T> list)
It takes a list that needs to be sorted as argument.
2. sort(List<T> list, Comparator<? super T>c)
It takes the list to be sorted and an object that implements Comparator interface as arguments.
Both these methods will be discussed in this article
Method 1: sort(List<T> list)
This method accepts a list as argument. Note that the list is generic. This is because it can contain objects of any type.
Objects of the list must implement Comparable
interface.java.util.Comparable
interface defines the method of ordering objects of a class.
It defines a way in which the objects should be compared while sorting.
This interface has a compareTo()
method which compares two objects based on single or multiple fields.
This method takes an object as argument and returns a value
- <0 if the object on which
compareTo()
is called is lesser than the supplied argument, - 0 if both the objects are equal, and
- >0 if the object on which
compareTo()
is called is greater than the supplied object.
If you want to sort a list of objects of a class, then the class should implement java.util.Comparable
interface and its compareTo()
method.
This method will define on what basis(or on which fields), the objects should be sorted.
Thus, if you want to sort a list of you own User class, then define this class as shown below.
import java.util.Comparable; //The User class public class User implements Comparable { // age of user. We need to sort on this int age; // constructor public User(int age) { this.age = age; } public int getAge() { return age; } public void setAge(int age) { this.age = age; } /* Since the class implements Comparable, * we need to provide compareTo() */ implementation @Override public int compareTo(User o) { // return the difference between ages of two users return this.age - o.getAge(); } }
As you can see, compareTo()
method compares objects on the basis of age.
Below is the code which creates different User
objects, add them to a list and then sort it.
Note that the program first prints the unsorted list and then the sorted list.
import java.util.Collections; //main class public class Sorter { public static void main(String[] args) { // create a list List list = new ArrayList(); // create users User user1 = new User(10); User user2 = new User(20); User user3 = new User(92); User user4 = new User(1); // add users to list list.add(user1); list.add(user2); list.add(user3); list.add(user4); System.out.println("Before Sorting..."); // iterate over unsorted list for (User u : list) { // this will print 10,20,92,1. System.out.println("User age: " + u.getAge()); } // now sort the list Collections.sort(list); System.out.println("After Sorting..."); // iterate over sorted list for (User u : list) { // this prints 1,10,20,92 System.out.println("User age: " + u.getAge()); } } }
Above code prints
Before Sorting…
User age: 10
User age: 20
User age: 92
User age: 1
After Sorting…
User age: 1
User age: 10
User age: 20
User age: 92
See! our list is sorted on the basis of age.
Similarly, if you want to sort the list of objects on some other field, then modify the compareTo()
method.
Above example uses an enhanced for loop to iterate over the list of objects but you can use other methods to iterate over the list.
This method can also be used to sort a list of strings in reverse order alphabetically.
Method 2: Sort with custom comparator
There is an overloaded version of Collections.sort()
, which accepts two arguments:
1. List to be sorted,
2. An object that implements Comparator
interface.
and sorts the list as per the logic defined in comparator object.
java.util.Comparator
interface has a compare()
method which takes two objects as arguments and returns an integer whose value can be
- <0 if the first object is lesser than the second,
- 0 if both the objects are equal, and
- >0 if the first object is greater than the second.
This method is useful when you cannot modify the class whose objects need to be sorted, you could then supply an external comparator to sort()
.
Example that sorts a list of objects with this method is given below.
import java.util.Collections; import java.util.Comparator; // compartor class class AgeComparator implement Comparator<User> { @Override public int compare(User u1, User u2) { // compare ages return u1.getAge() - u2.getAge(); } } //main class public class Sorter { public static void main(String[] args) { // create a list List list = new ArrayList(); // create users User user1 = new User(10); User user2 = new User(20); User user3 = new User(92); User user4 = new User(1); // add users to list list.add(user1); list.add(user2); list.add(user3); list.add(user4); System.out.println("Before Sorting..."); // iterate over unsorted list for (User u : list) { // this will print 10,20,92,1. System.out.println("User age: " + u.getAge()); } // create an object of comparator AgeComparator c = new AgeComparator(); // now sort the list using comparator Collections.sort(list, c); System.out.println("After Sorting..."); // iterate over sorted list for (User u : list) { // this prints 1,10,20,92 System.out.println("User age: " + u.getAge()); } } }
Note the class that implements Comparator
overrides its compare()
method and returns an integer which is a difference between age of User objects.
Output of this program is
Before Sorting…
User age: 10
User age: 20
User age: 92
User age: 1
After Sorting…
User age: 1
User age: 10
User age: 20
User age: 92
Instead of creating a separate class and object for Comparator
, implementation of compare
can be supplied inline to sort
method as an anonymous inner class as shown below.
Collections.sort(list, new Comparator<User>() { @Override public int compare(User u1, User u2) { return u1.getAge() - u2.getAge(); } });
Sort list objects java 8
Starting java 8, the implementation of compare method supplied to sort can be further be shortened by writing it as a Lambda expression as shown below.
Collections.sort(list, (o1, o2) -> o1.getAge() - o2.getAge());
Type of arguments of a Lambda expression are inferred by the compiler according to the context.
Let’s tweak in
- In order to sort the list using
sort
method ofjava.util.Collections
class, the elements of the list MUST implementjava.lang.Comparable
interface.
This is becauseCollections.sort()
internally casts the objects tojava.lang.Comparable.
If the object has not implementedComparable
, a compiler error will be generated. - If you declare a class to implement
java.lang.Comparable
and you do not provide implementation or override equals() method then a compiler error will be raised. - The signature of the compareTo() method in the class implementing
java.lang.Comparable
should exactly match the signature ofcompareTo()
method inComparable
interface.
That is,public int compareTo(T o);
If you change the return type of the method implementation in your class, you will face a compiler error The return type is incompatible with Comparable.compareTo(User) Collections.sort()
method internally converts list to an array and this array is then iterated.- During iteration,
compareTo()
method is invoked on all elements of array one by one.
One object calls it and object at the next location is passed as an argument to this method as:(array[j-1]).compareTo(array[j])
This is when thecompareTo
method defined in our class gets called. - Object equality is calculated based on the criteria or the field chosen in the
compareTo()
method implementation.
In our case, it was the age but it can be anything such as alphabetical order of user name. - List objects can be sorted on multiple fields and this should be defined in
compareTo()
orcompare()
methods.
Hope you clearly understood how to sort a list of objects by field using Collections.sort()
method.