What is comparator
java.util.Comparator
is an interface in java used for sorting or ordering of collections such as a List, Set, array etc.
A comparator is mostly used to sort a collection of custom or user defined objects which do not possess a natural ordering.
Natural ordering means sorting by alphabetical order, numbers etc.
A list of numbers can be sorted in order of increasing or decreasing order but on what basis should an employee list be sorted.
Comparator is used to specify this criteria on which the objects should be ordered.
compare method
Comparator is a functional interface having only one abstract method named
compare()
which is used to order objects of a collection.Signature of
compare()
method is
int compare(T objectOne, T objectTwo)
where T
is a generic type which is of the type of objects that you want to order.
compare()
method returns an integer value whose possible values are
- 0 : If the values compared are equal,
- Greater than 0(or positive) : If first object is greater than second,
- Lesser than 0(or negative) : If first object is lesser than second.
How comparator works
java.util.Collections
and java.util.Arrays
class have sort()
methods which are used for sorting a list and array respectively.
Both these classes have an overloaded method which accepts a Comparator as argument, used for sorting list or array of user defined classes as shown below.
Collections.sort(List<T> list, Comparator<? super T> c)
Arrays.sort(T[] a, Comparator<? super T> c)
where T is a generic type.
Note that the type of Comparator should be the same as the type of List or array.
There are two ways to supply the Comparator object to sort()
method.
1. As an object of a class that implements java.util.Comparator
interface.
This class should contain implementation of compare()
method which defines the ordering criteria for the objects of its class.
2. As an anonymous inner class that implements compare()
method(explained later).
Comparator example
Suppose there is a list of book objects. Book
class is as below.
public class Book { private int price; private int pages; private String title; public Book(String title, int price, int pages) { this.title = title; this.price = price; this.pages = pages; } public int getPrice() { return price; } public void setPrice(int price) { this.price = price; } public int getPages() { return pages; } public void setPages(int pages) { this.pages = pages; } public String getTitle() { return title; } public void setTitle(String title) { this.title= title; } public String toString() { return "[Title = " + title + ", price = " + price + ", pages = " + pages + "]"; } }
Let us create a list of book objects and print each of the book objects.
// create list List<Book> books = new ArrayList<Book>(); // create book objects Book bookOne = new Book("Think and grow rich", 99, 250); Book bookTwo = new Book("Rich Dad Poor Dad", 318, 336); Book bookThree = new Book("Sherlock homes", 113, 536); Book bookFour = new Book("The richest man in babylon", 129, 152); // add objects to list books.add(bookOne); books.add(bookTwo); books.add(bookThree); books.add(bookFour); // iterate over list for (Book book : books) { System.out.println(book); }
This prints
As visible from the above output, there is no ordering among book objects.
- Create a class that implements
java.util.Comparator
interface. - Implement
compare()
method in this class. It should contain the criteria to sort objects.
import java.util.Comparator; public class PageOrder implements Comparator<Book> { public int compare(Book b1, Book b2) { return b1.getPages() - b2.getPages(); } }
compare()
method defined above will sort book objects in ascending order of pages.
Now let us sort the list of books using this Comparator.
import java.util.Comparator; public class BookSorter { public static void main(String... a) { // create list List<Book> books = new ArrayList<Book>(); // create book objects Book bookOne = new Book("Think and grow rich", 99, 250); Book bookTwo = new Book("Rich Dad Poor Dad", 318, 336); Book bookThree = new Book("Sherlock homes", 113, 536); Book bookFour = new Book("The richest man in babylon", 129, 152); // add objects to list books.add(bookOne); books.add(bookTwo); books.add(bookThree); books.add(bookFour); // sort list of books Collectios.sort(books, new PageOrder()); // iterate over list for (Book book : books) { System.out.println(book); } } }
Above code will print
Look, the list of books is not sorted in ascending order of pages. If the list needs to be sorted in descending order of pages, then the compare()
method should be modified as below.
public int compare(Book b1, Book b2) { return b2.getPages() - b1.getPages(); }
Now try writing a Comparator to sort the list in ascending and descending order of book price.
In the above example, a separate class was created for implementing a Comparator. It is not convenient and permissible to create a new class always.
In such cases, you can define a Comparator at the same place where it is required using new operator and defining
compare()
method.This is called anonymous comparator and is implemented as an inner class as shown below.
Collections.sort(books, new Comparator<Book>() { public int compare(Book b1, Book b2) { return b1.getPages() - b2.getPages(); } });
You will only see new
operator with an interface only as an anonymous class since interface in java can not be instantiated.
Comparator using Lambda expression
Starting java 8, Comparator definition can be further simplified using a Lambda expression.
compare()
method can be implemented inline using its arguments and directly supplied to sort()
method as shown below.
Collections.sort(books, (Book b1, Book b2) -> { return b1.getPages() - b2.getPages(); });
sort()
can be defined as a Lambda expression because java.util.Comparator
is a functional interface.
Reverse comparator
Ordering of a list by Comparator can be reversed by modifying compare()
method. But many times, it is not possible to modify compare()
since the source code may not be available.
In such case, the order of list may be reversed using reversed()
method of java.util.Comparator
.
reversed()
is a default interface method added in java 8 and can be used as below.
PageOrder comparator = new PageOrder(); Collections.sort(books, comparator.reversed());
If the list to be sorted contains a
null
value, Comparator provides its handling using following methods.nullsFirst
It is a static interface method introduced in java 8 which accepts a comparator as argument. This method places
null
values before non-null values.In other words, it considers
null
values to be smaller than other values.Supply the comparator returned by this method to
sort()
method as shown below.
import java.util.Comparator; public class BookSorter { public static void main(String... a) { // create list List<Book> books = new ArrayList<Book>(); // create book objects Book bookOne = new Book("Think and grow rich", 99, 250); Book bookTwo = new Book("Rich Dad Poor Dad", 318, 336); Book bookThree = new Book("Sherlock homes", 113, 536); Book bookFour = new Book("The richest man in babylon", 129, 152); // add objects to list books.add(bookOne); books.add(bookTwo); books.add(bookThree); books.add(bookFour); // add null to list books.add(null); // create a comparator PageOrder comparator = new PageOrder(); // create comparator to handle nulls Comparator<Book> nullsFirstComparator = Comparator.nullsFirst(comparator); // sort with null handling Collections.sort(books, nullsFirstComparator); // iterate over list for (Book book : books) { System.out.println(book); } } }
Above code prints
See, null
is printed at first position while other books are sorted in increasing order of pages which is as per the initial comparator implementation.
Above code can be shortened by writing below one liner
Collections.sort(books, Comparator.nullsFirst(new PageOrder()));
nullsLast
This method puts null
values as last or it considers null values to be greater than non-null values.
It is also a static interface method accepting a comparator as argument and returns a new comparator with null
values handled. Example,
import java.util.Comparator; public class BookSorter { public static void main(String... a) { // create list List<Book> books = new ArrayList<Book>(); // create book objects Book bookOne = new Book("Think and grow rich", 99, 250); Book bookTwo = new Book("Rich Dad Poor Dad", 318, 336); Book bookThree = new Book("Sherlock homes", 113, 536); Book bookFour = new Book("The richest man in babylon", 129, 152); // add objects to list books.add(bookOne); books.add(bookTwo); books.add(bookThree); books.add(bookFour); // add null to list books.add(null); // create a comparator PageOrder comparator = new PageOrder(); // create comparator to handle nulls Comparator<Book> nullsLastComparator = Comparator.nullsLast(comparator); // sort with null handling Collections.sort(books, nullsLastComparator); // iterate over list for (Book book : books) { System.out.println(book); } } }
which prints
Code above can be written as one-liner
Collections.sort(books, Comparator.nullsLast(new PageOrder()));
This article explained the concept of Comparator interface in java with examples. Hit the clap if the article was useful.