Java Comparator

Jakob Jenkov
Last update: 2020-10-04

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();
    }
}

Jakob Jenkov

Featured Videos

Java Generics

Java ForkJoinPool

P2P Networks Introduction



















Close TOC
All Tutorial Trails
All Trails
Table of contents (TOC) for this tutorial trail
Trail TOC
Table of contents (TOC) for this tutorial
Page TOC
Previous tutorial in this tutorial trail
Previous
Next tutorial in this tutorial trail
Next