[java] Why should a Java class implement comparable?

Why is Java Comparable used? Why would someone implement Comparable in a class? What is a real life example where you need to implement comparable?

This question is related to java

The answer is


Quoted from the javadoc;

This interface imposes a total ordering on the objects of each class that implements it. This ordering is referred to as the class's natural ordering, and the class's compareTo method is referred to as its natural comparison method.

Lists (and arrays) of objects that implement this interface can be sorted automatically by Collections.sort (and Arrays.sort). Objects that implement this interface can be used as keys in a sorted map or as elements in a sorted set, without the need to specify a comparator.

Edit: ..and made the important bit bold.


The fact that a class implements Comparable means that you can take two objects from that class and compare them. Some classes, like certain collections (sort function in a collection) that keep objects in order rely on them being comparable (in order to sort you need to know which object is the "biggest" and so forth).


An easy way to implement multiple field comparisons is with Guava's ComparisonChain - then you can say

   public int compareTo(Foo that) {
     return ComparisonChain.start()
         .compare(lastName, that.lastName)
         .compare(firstName, that.firstName)
         .compare(zipCode, that.zipCode)
         .result();
   }

instead of

  public int compareTo(Person other) {
    int cmp = lastName.compareTo(other.lastName);
    if (cmp != 0) {
      return cmp;
    }
    cmp = firstName.compareTo(other.firstName);
    if (cmp != 0) {
      return cmp;
    }
    return Integer.compare(zipCode, other.zipCode);
  }
}

Comparable is used to compare instances of your class. We can compare instances from many ways that is why we need to implement a method compareTo in order to know how (attributes) we want to compare instances.

Dog class:

package test;
import java.util.Arrays;

public class Main {

    public static void main(String[] args) {
        Dog d1 = new Dog("brutus");
        Dog d2 = new Dog("medor");
        Dog d3 = new Dog("ara");
        Dog[] dogs = new Dog[3];
        dogs[0] = d1;
        dogs[1] = d2;
        dogs[2] = d3;

        for (int i = 0; i < 3; i++) {
            System.out.println(dogs[i].getName());
        }
        /**
         * Output:
         * brutus
         * medor
         * ara
         */

        Arrays.sort(dogs, Dog.NameComparator);
        for (int i = 0; i < 3; i++) {
            System.out.println(dogs[i].getName());
        }
        /**
         * Output:
         * ara
         * medor
         * brutus
         */

    }
}

Main class:

package test;

import java.util.Arrays;

public class Main {

    public static void main(String[] args) {
        Dog d1 = new Dog("brutus");
        Dog d2 = new Dog("medor");
        Dog d3 = new Dog("ara");
        Dog[] dogs = new Dog[3];
        dogs[0] = d1;
        dogs[1] = d2;
        dogs[2] = d3;

        for (int i = 0; i < 3; i++) {
            System.out.println(dogs[i].getName());
        }
        /**
         * Output:
         * brutus
         * medor
         * ara
         */

        Arrays.sort(dogs, Dog.NameComparator);
        for (int i = 0; i < 3; i++) {
            System.out.println(dogs[i].getName());
        }
        /**
         * Output:
         * ara
         * medor
         * brutus
         */

    }
}

Here is a good example how to use comparable in Java:

http://www.onjava.com/pub/a/onjava/2003/03/12/java_comp.html?page=2


OK, but why not just define a compareTo() method without implementing comparable interface. For example a class City defined by its name and temperature and

public int compareTo(City theOther)
{
    if (this.temperature < theOther.temperature)
        return -1;
    else if (this.temperature > theOther.temperature)
        return 1;
    else
        return 0;
}

Comparable defines a natural ordering. What this means is that you're defining it when one object should be considered "less than" or "greater than".

Suppose you have a bunch of integers and you want to sort them. That's pretty easy, just put them in a sorted collection, right?

TreeSet<Integer> m = new TreeSet<Integer>(); 
m.add(1);
m.add(3);
m.add(2);
for (Integer i : m)
... // values will be sorted

But now suppose I have some custom object, where sorting makes sense to me, but is undefined. Let's say, I have data representing districts by zipcode with population density, and I want to sort them by density:

public class District {
  String zipcode; 
  Double populationDensity;
}

Now the easiest way to sort them is to define them with a natural ordering by implementing Comparable, which means there's a standard way these objects are defined to be ordered.:

public class District implements Comparable<District>{
  String zipcode; 
  Double populationDensity;
  public int compareTo(District other)
  {
    return populationDensity.compareTo(other.populationDensity);
  }
}

Note that you can do the equivalent thing by defining a comparator. The difference is that the comparator defines the ordering logic outside the object. Maybe in a separate process I need to order the same objects by zipcode - in that case the ordering isn't necessarily a property of the object, or differs from the objects natural ordering. You could use an external comparator to define a custom ordering on integers, for example by sorting them by their alphabetical value.

Basically the ordering logic has to exist somewhere. That can be -

  • in the object itself, if it's naturally comparable (extends Comparable -e.g. integers)

  • supplied in an external comparator, as in the example above.


When you implement Comparable interface, you need to implement method compareTo(). You need it to compare objects, in order to use, for example, sorting method of ArrayList class. You need a way to compare your objects to be able to sort them. So you need a custom compareTo() method in your class so you can use it with the ArrayList sort method. The compareTo() method returns -1,0,1.

I have just read an according chapter in Java Head 2.0, I'm still learning.


Most of the examples above show how to reuse an existing comparable object in the compareTo function. If you would like to implement your own compareTo when you want to compare two objects of the same class, say an AirlineTicket object that you would like to sort by price(less is ranked first), followed by number of stopover (again, less is ranked first), you would do the following:

class AirlineTicket implements Comparable<Cost>
{
    public double cost;
    public int stopovers;
    public AirlineTicket(double cost, int stopovers)
    {
        this.cost = cost; this.stopovers = stopovers ;
    }

    public int compareTo(Cost o)
    {
        if(this.cost != o.cost)
          return Double.compare(this.cost, o.cost); //sorting in ascending order. 
        if(this.stopovers != o.stopovers)
          return this.stopovers - o.stopovers; //again, ascending but swap the two if you want descending
        return 0;            
    }
}

For example when you want to have a sorted collection or map