Thursday, 6 July 2017

How to sort an ArrayList of Objects using Comparator in Java 8 - Ascending and Descending Order

There are a lot of examples of Sorting ArrayList in Java on the internet, but most of them use either String or Integer objects to explain sorting, which is not enough, because in real world you may have to sort a list of custom objects e.g. your domain or business objects like Employee, Book, Order, Trade etc. In order to sort an ArrayList of objects, you need two things, first a class to provider ordering and a method to provide sorting. If you know about ordering and sorting in Java then you know that Comparable and Comparator class is used to provide the ordering for objects. The Comparable interface provides natural order e.g. lexicographic order of String or name for Employees, while Comparator is used to provide custom order. It gives you the flexibility to sort your objects on the parameter you want e.g. you can sort a list of Coupon objects on the percentage discount, expiry dates, or based upon the total cost.

Once you have got ordering for your object, you can use Collections.sort() method to sort your ArrayList of objects. This method accepts an ArrayList and sorts them in place. Internally it uses MergeSort to sort your list of objects. This method is a good example of strategy pattern because it uses the Comparator you provide to sort your objects, which means you can sort the same list of objects into different order by just changing the Comparator.

For example, You can sort an ArrayList of Objects in descending order by just reversing the order of your Comparator. The JDK API provides another convenient method Collections.reverseOrder(Comparator c) which return a comparator with the opposite order of given Comparator.

Btw, this is not the only way to sort an ArrayList of objects in Java. If you want you can use Comparable to sort in the natural order and in the decreasing order of natural order imposed by Comparator. the JDK 8 release also added a couple of methods on both java.util.Comparator class and java.util.List to make sorting easier.

For example, you can also use List.sort() method to sort a List of objects. This is similar to Collections.sort() and you can use it to sort a List of objects using both Comparator and Comparable. This method accepts a Comparator and sort elements based upon that, but if you want to sort on the natural order, just don't supply a Comparator and pass null.

The List.sort() of Java 8 will then sort the list on order imposed by Comparable.

Sorting a List of Objects using Comparator 


In this article, I'll show you how to sort a List of objects in both ascending and descending order by using Comparator. I have a domain object called Course, which contains title and price of the course, a title is String and fee are long value. In order to sort the list of courses e.g. REST With Spring, Learn Spring Security, and Introduction to Spring MVC 4, some of my recommended course to learn Spring, I have created two Comparators, a title comparator which sorts based upon title and a fee comparator which sorts based upon fee. These Comparator implementation classes use Java 8 lambdas to implement compare() method as shown here, and sort the list of objects into ascending order of title and fee.

In order to sort in the reverse order i.e. descending order, you don't need to create a separator Comparator, instead, you just need to reverse the order of existing comparator using Collections.reverseOrder(Comparator c) method. If you are using Java 8, then you can also use the reversed() method of java.util.Comparator which returns a comparator that imposes the reverse ordering of this comparator.

In fact, JDK 8 has added several new methods to facilitate sophisticated sorting in Java 8 e.g. comparing() and thenComparing() method to chain multiple comparators.

Java Program to Sort an ArrayList of Object using Comparator


Here is our Java program which will sort the list of courses using custom comparators. In this article, I have created two implementations of java.util.Comparator interface, one called TitleComparator, which sort the list of courses on their title and other, called FeeComparator which sorts the list of courses on their price.

I have also used new List.sort() method of JDK 8 for sorting. Though, you can use Collection.sort() if you are not using JDK 8, just replace the List.sort() with Collections.sort() and the program should work fine.

Also, I have used the lambda expression to implement our Comparators as oppose to Anonymous class which we used earlier. You can see your Comparator implementation has become quite simple and you can write them in just one line.

ArrayList, Oracle Objects, Java 8, Ascending and Descending Order

Java Program to sort an ArrayList using Comparator

import java.util.ArrayList;
import java.util.Collections;
import java.util.Comparator;
import java.util.Iterator;
import java.util.List;
import java.util.stream.Collectors;

/*
* Java Program to sort an ArrayList with objects using Comparator
*/

public class Main {

public static void main(String[] args) { 

// sorting an ArrayList of object using Comparator
Course restWithSpring = new Course("REST with Spring", 99);
Course learnSpringSecurity = new Course("Learn Spring Security", 110);
Course introToSpringMVC4 = new Course("Introduction to Spring MVC 4", 0);

List<Course> listOfCourses = new ArrayList<>();
listOfCourses.add(restWithSpring);
listOfCourses.add(learnSpringSecurity);
listOfCourses.add(introToSpringMVC4);

// let's sort this list of course by title first using Comparator

Comparator<Course> titleComparator = (c1, c2) -> c1.title().compareTo(c2.title()); 
Comparator<Course> feeComparator = (c1, c2) -> (int) (c1.fee() - c2.fee());

// printing ArrayList before sorting
System.out.println("unsorted list: " + listOfCourses);

// sorting list of objects using comparator - using title on ascending order
listOfCourses.sort(titleComparator);

// printing ArrayList after sorting in ascending order
System.out.println("sorted list in ascending order of title: " + listOfCourses);

// sorting arraylist of objects using comparator - using fee on ascending order
listOfCourses.sort(feeComparator);

// printing ArrayList after sorting in ascending order
System.out.println("sorted list in ascending order of fee: " + listOfCourses);

// sorting array list in descending order of title
listOfCourses.sort(Collections.reverseOrder(titleComparator));
System.out.println("sorted list in descending order of title: " + listOfCourses);

// sorting arraylist in descending order of fee
listOfCourses.sort(Collections.reverseOrder(feeComparator));
System.out.println("sorted list in descending order of fee: " + listOfCourses);

}

}

class Course{
String title;
long fee;

public Course(String title, long fee){
this.title = title;
this.fee = fee;
}

public String title(){
return title;
}

public long fee(){
return fee;
}

@Override
public String toString() {
return String.format(title + "@ " + fee);
}
}

Output:

unsorted list: [REST with Spring@ 99, Learn Spring Security@ 110,
 Introduction to Spring MVC 4@ 0]
sorted list in ascending order of title: [Introduction to Spring MVC 4@ 0,
 Learn Spring Security@ 110, REST with Spring@ 99]
sorted list in ascending order of fee: [Introduction to Spring MVC 4@ 0,
 REST with Spring@ 99, Learn Spring Security@ 110]
sorted list in descending order of title: [REST with Spring@ 99, 
Learn Spring Security@ 110, Introduction to Spring MVC 4@ 0]
sorted list in descending order of fee: [Learn Spring Security@ 110,
 REST with Spring@ 99, Introduction to Spring MVC 4@ 0]

From the output, it's clear that our sorting works as expected. In the ascending order of title, Introduction to Spring MVC 4 comes first because it starts with the letter "I", while other starts with letter "L" and letter "R". In the descending order, the "REST with Spring" comes first because of the same reason. While, in the ascending order of fee, again, Introduction to Spring MVC 4 comes first because it is the least expensive out of these three courses.

That's all about how to sort an ArrayList of Objects using Comparator in Java. You have learned to sort ArrayList in both ascending and descending order using Comparator. As I said, you don't need to create two comparators, instead, you just create a comparator to sort the list of objects based upon any attribute you want and then use the Collections.reverseOrder() method to reverse the order imposed by Comparator. It accepts a comparator and then sorts the elements in the array list in the reverse order of that comparator. This way you can sort the list of objects in descending order.