Java Comparators — When comparison doesn’t go natural
Have you ever tried to compare two objects based on their size? or Create a todo list application to prioritize your work based on its type?
Java inherits two popular methods equals(Object o) and hashCode() from its Object class for comparing two objects based on their values inside and their address locations (via hashcodes).
Operators like < (less than) and > (greater than) do not go well with objects in Java. The Object class does not provide any methods for “less than” or “greater than” comparison. For this type of comparison, java follows the natural ordering of these objects.
Now, the question comes, what is natural ordering? Well technically, the natural ordering defines some rules that govern the relative placement of elements/values/objects based on their type. For example, String values will be sorted in lexicographical order, Date values will be sorted in chronological order, Integer values will be sorted in ascending/descending (Signed numeric) order, and so on.
Java provides a standard way for comparing its objects based on their natural ordering by implementing compareTo(Object o) method of the Comparable interface. Here’s the syntax for using a Comparable interface in java.
public interface Comparable<T> {
public int compareTo(T other);
}
A call to A.compareTo(B ) should return:
- a value < 0, if A comes “before” B in the ordering,
- a value > 0, if A comes “after” B in the ordering,
- or exactly 0 if A and B are considered “equal” in the ordering
Let’s suppose we wish to develop a movie database application (just like IMDb) to rate movies based on certain parameters. Consider a Movie object that has members like rating, name, year of release, critics score etc. Suppose, we wish to sort a list of Movies based on their year of release. Since, year is a signed numeric value (Integer), it’ll be ordered naturally.
We can implement the Comparable interface with the Movie class, and we can override the compareTo() method as follows:
// sort movies by year of release
public int compareTo(Movie m)
{
return this.year — m.year;
}
so far so good…
Now, let's say, the client wants us to order movies in our Movie database application based on critics' score and user’s rating.
This is true for most real-life scenarios, as we want to compare objects based on different parameters. This is the situation where we use Java Comparator interface since Comparable.compareTo(Object o) works only on default comparison (i.e., natural ordering) and we cannot customize it as per our requirements.
Comparators, unlike Comparable, is external to the element type we are comparing.
- It allows us to define multiple orderings for the same type of object
- It allows us to define a specific ordering for an object type even if there’s no obvious “natural ordering” for that type
We can create multiple separate classes (that implements Comparator interface) to compare objects as per requirements. Here’s the syntax for using Comparator interface in java:
public interface Comparator<T>{
public int compare(T first, T second);
}
Now, to compare movies based on their critic's score and user’s rating, we can do the following:
- Create different classes that implements Comparator (and thus compare()) to customize our comparison
// using compare(Object o1, Object o2) to compare movies based on ciritic’s score
public int compare(Movie m1, Movie m2)
{
if (m1.getCriticScore() < m2.getCriticScore()) return -1;
if (m1.getCriticScore() > m2.getCriticScore()) return 1;
else return 0;
}
// using compare(Object o1, Object o2) to compare movies based on user’s rating
public int compare(Movie m1, Movie m2)
{
if (m1.getUserRating() < m2.getUserRating()) return -1;
if (m1.getUserRating() > m2.getUserRating()) return 1;
else return 0;
}
To summarize, use Comparable when you want to compare objects based on their natural ordering (the Object inherently knows how to compare itself) and use Comparator when you want to customize your comparison based on different parameters/attributes of your object.
You can refer to the official documentation of Comparator interface defined in Java Standard API by following the given link.