Why should a Java class implement comparable?

Java

Java Problem Overview


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?

Java Solutions


Solution 1 - Java

Here is a real life sample. Note that String also implements Comparable.

class Author implements Comparable<Author>{
    String firstName;
    String lastName;
    
    @Override
    public int compareTo(Author other){
        // compareTo should return < 0 if this is supposed to be
        // less than other, > 0 if this is supposed to be greater than 
        // other and 0 if they are supposed to be equal
        int last = this.lastName.compareTo(other.lastName);
        return last == 0 ? this.firstName.compareTo(other.firstName) : last;
    }
}

later..

/**
 * List the authors. Sort them by name so it will look good.
 */
public List<Author> listAuthors(){
    List<Author> authors = readAuthorsFromFileOrSomething();
    Collections.sort(authors);
    return authors;
}

/**
 * List unique authors. Sort them by name so it will look good.
 */
public SortedSet<Author> listUniqueAuthors(){
    List<Author> authors = readAuthorsFromFileOrSomething();
    return new TreeSet<Author>(authors);
}

Solution 2 - Java

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.

Solution 3 - Java

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.

Solution 4 - Java

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).

Solution 5 - Java

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

Solution 6 - Java

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

Solution 7 - Java

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

Solution 8 - Java

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

Solution 9 - Java

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.

Solution 10 - Java

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

Attributions

All content for this solution is sourced from the original question on Stackoverflow.

The content on this page is licensed under the Attribution-ShareAlike 4.0 International (CC BY-SA 4.0) license.

Content TypeOriginal AuthorOriginal Content on Stackoverflow
QuestionLondonView Question on Stackoverflow
Solution 1 - JavaEnno ShiojiView Answer on Stackoverflow
Solution 2 - JavaSteve B.View Answer on Stackoverflow
Solution 3 - JavaQwerkyView Answer on Stackoverflow
Solution 4 - JavaAmir RachumView Answer on Stackoverflow
Solution 5 - JavaarvimanView Answer on Stackoverflow
Solution 6 - JavaRan AdlerView Answer on Stackoverflow
Solution 7 - JavaFernando MiguélezView Answer on Stackoverflow
Solution 8 - JavanonoView Answer on Stackoverflow
Solution 9 - JavalxknvlkView Answer on Stackoverflow
Solution 10 - JavaAle BView Answer on Stackoverflow