Introduction
There is a lot of confusion among beginners about Comparators and Comparable. The main reason is the lack of understanding about what they are and the difference between them.
Background
CompareTo – Method that compares between the current element that initiates the method and another object that passed in the method. The method returns a positive number if the current element is bigger than the passed element, negative if it's smaller and 0 if they are equal.
Natural ordering – The most suitable parameter to be used to compare at the current class. For example, Employee
often compared by their "Performances
".
Understanding Definitions
Comparable
Object that can be compared with other objects by their narutal ordering.
Implementing Comparable
means "I can compare myself with another object." This is typically useful when there's a single natural default comparison. © Jon Skeet.
Example: If I have an IdCard
class, then the natural ordering for this scenario is by Id
number.
Comparator
Independent specific class that is targeted for comparing two objects by specific field.
Comparators allow us to add more ways for comparing objects.
Implementing Comparator means "I can compare two other objects." This is typically useful when there are multiple ways of comparing two instances of a type. © Jon Skeet.
Example: We can compare 2 people by properties like Age
, Height
, etc.
Comparable
Person.java
public class Person implements Comparable<Object> {
public int id;
public String name;
public int age;
public int height;
public Person(int id, String name, int age, int height) {
this.id = id;
this.name = name;
this.age = age;
this.height = height;
}
@Override
public int compareTo(Object o) {
return this.id - ((Person)o).id;
}
@Override
public String toString() {
return String.format("[Name: %s/Age: %d/Height: %d]", name, age, height);
}
}
To illustrate the Comparable
interface, I choose to create a simple Person
class. I gave this class a constructor with the following fields: id
, name
, age
and height
. I've used the Comparable<Object>
interface and implemented its compareTo
method. Because Person
object in my program is compared by id
, I've implemented the compareTo
to be subjected to the object id
member. This can easily be changed to suit your own Class
. We can now compare the person
objects with other person
objects, a comparison will look like this:
System.out.println("Is Bar id bigger than Sam ? " + pBar.compareTo(pSam));
Output
System.out.println("Is Bar id bigger than Sam ? " + pBar.compareTo(pSam));
Another Example: A Man's Wallet
We know that wallet will usually be compared by the amount of money it's containing. So a suitable Wallet
class will look like this:
public class Wallet implements Comparable<Object> {
public int money = 0;
public String name;
public Wallet(String name, int money) {
this.name = name;
this.money = money;
}
@Override
public int compareTo(Object o) {
return this.money - ((Wallet)o).money;
}
}
Comparators
Comparators are independent classes which implement "Comparator
" interface.
Comparators main usages are for sorting, each comparator will implement inside compareTo
their own sort logic. And later, the comparator will be passed through a sorting algorithm that will be used the passed comparator sorting logic.
For example: HeightComparator
will compare the height
field from two objects.
HeightComparator.java
import java.util.Comparator;
public class HeightComparator implements Comparator<Object> {
@Override
public int compare(Object o1, Object o2) {
int p1 = ((Person)o1).height;
int p2 = ((Person)o2).height;
return p1 - p2;
}
}
This comparator is casting both received objects into Person
objects and returning a positive number when the first object is bigger than the second, else negative number when the second object is bigger than the first one, otherwise it is returning zero because both of them are equal.
Comparator has another usage. We can use it without sorting the whole collection, by creating the targeted comparator and then passing it the objects we want to compare.
Exploring the Examples
MainClass.java
ArrayList<Person> peoples = new ArrayList<Person>();
Person pOrel = new Person(1, "Orel", 27, 186);
Person pBar = new Person(2, "Bar", 28, 165);
Person pSam = new Person(3, "Sam", 25, 170);
peoples.add(pOrel);
peoples.add(pBar);
peoples.add(pSam);
I created an Person
ArrayList
to hold our collection. I've created 3 Person
instances and added them into our collection.
System.out.println("Is Bar id bigger than Sam ? " + pBar.compareTo(pSam));
I've tested the Person
compare method by comparing to see if pBar
is bigger than pSam
, as we know this will use Person
compareTo
method to see if pBar
id number is bigger than pSam
id number (false, pSam
id is bigger).
Output
Is Bar id bigger than Sam ? -1
System.out.println("Does Orel taller than Sam ? " +
new HeightComparator().compare(pOrel, pSam));
I've used specific comparator in order to discover if pOrel
is taller than pSam
.
Output
Does Orel taller than Sam ? 16
Collections.sort(peoples, new AgeComparator());
System.out.println("Compare by Age");
MyLibrary.printObjects(peoples);
I'm passing our sorting algorithm peoples
collection and AgeComparator
in order to sort our collection by the logic inside the compare
method inside AgeComparator
. Then using a normal static
method to print the result.
Output
Compare by Age
[Name: Sam/Age: 25/Height: 170] [Name: Orel/Age: 27/Height: 186]
[Name: Bar/Age: 28/Height: 165]
Conclusion
Using Comparable and Comparators can easily simplify your code when tasks for sorting are needed. It will make your code more generic, readable and clean.
History
- 28th December, 2013: Initial post