Java Comparator
Jakob Jenkov |
The Java Comparator interface, java.util.Comparator
, represents a component that can compare two objects so they
can be sorted using sorting functionality in Java. When sorting e.g a
Java List you can pass a Java Comparator to the sorting method. The Comparator is
then used to compare the objects in the List during sorting.
The Java Comparator interface is different from the Java Comparable interface. The Comparator is an external component to the objects being compared, whereas the Comparable is an interface implemented by the compared objects themselves. The sort order of the Comparable is said to be the objects' natural sorting order - whereas the Comparator's sort order is not.
Java Comparator Interface Definition
The Java Comparator interface is located in the java.util
package.
The Java Comparator interface definition looks like this:
public interface Comparator<T> { public int compare(T o1, T o2); }
Notice that the Java Comparator interface only has a single method. This method, the compare()
method, takes two objects which the Comparator implementation is intended to compare. The compare()
method returns an int
which signals which of the two objects was larger. The semantics of the
return values are:
- A negative value means that the first object was smaller than second object.
- The value 0 means the two objects are equal.
- A positive value means that the first object was larger than the second object.
Transitive Comparison
Note, that it is a requirement when implementing the Java Comparator interface, that the implementation respects the following transitive comparison characteristics:
If A is larger than B, and B is larger than C, then A must also be larger than C.
Implementing the Java Comparator Interface
Imagine you have the following Spaceship class that you would like to be able to compare instances of:
public class Spaceship implements Comparable<Spaceship> { private String spaceshipClass = null; private String registrationNo = null; public Spaceship(String spaceshipClass, String registrationNo) { this.spaceshipClass = spaceshipClass; this.registrationNo = registrationNo; } public String getSpaceshipClass() { return spaceshipClass; } public String getRegistrationNo() { return registrationNo; } @Override public int compareTo(Spaceship other) { int spaceshipClassComparison = this.spaceshipClass.compareTo(other.spaceshipClass); if(spaceshipClassComparison != 0) { return spaceshipClassComparison; } return this.registrationNo.compareTo(other.registrationNo); } }
Notice that the Spaceship class already implements the Comparable interface which compares Spaceship objects on spaceshipClass first, and then registrationNo. This is not necessary, by the way, if you want to compare objects using a Comparator. Whether or not the objects implements the Comparable interface is irrelevant when comparing objects using a Comparator.
Now imagine you want to sort Spaceship objects only based on their registration number, and ignore the spaceshipClass. Here is a Java Comparator implementation that will do that:
import java.util.Comparator; public class SpaceshipComparator implements Comparator<Spaceship> { @Override public int compare(Spaceship o1, Spaceship o2) { return o1.getRegistrationNo().compareTo(o2.getRegistrationNo()); } }
First, notice how the SpaceshipComparator class implements the Comparator interface with the type
Spaceship specified inside the < > characters ( implements Comparator<Spaceship>
).
This sets the type of objects this Comparator implementation can compare to Spaceship objects.
Setting the generic type of the Comparator implementation to Spaceship means that the parameter types
of the compare()
method can be set to Spaceship
, and not Object
as it would have been - if no generic type had been specified ( implements Comparator
).
A Java Comparator implementation is pretty much always specialized to be able to compare objects of a specific type (class), so specifying a generic type in your Comparator implementation almost always makes sense.
Second, notice how the compare()
method returns the registrationNo of the first
Spaceship parameter compared to the registrationNo of the second Spaceship parameter. This is
a totally valid way of implementing a Comparator.
Comparing Numbers
If your Comparator implementation needs to compare numbers from the compared objects, an easy way is to simply subtract the two numbers from each other and return that value.
Imagine if the registrationNo variable of the Spaceship class was an int
instead,
so getRegistrationNo()
would return an int
. The registrationNo of two
Spaceship objects could then be compared like this:
import java.util.Comparator; public class SpaceshipComparator implements Comparator<Spaceship> { @Override public int compare(Spaceship o1, Spaceship o2) { return o1.getRegistrationNo() - o2.getRegistrationNo(); } }
Tweet | |
Jakob Jenkov |