Comparable and Comparator Interfaces in Java

Assume you have a list of names, then you know how to sort these list of people i.e, on the basic of alphabetical order (lexical order). Similar for list of identification numbers.
But when we have a container containing a list of Person object .Now, how you compare two Person objects?
There are many number of comparable attributes, such as SSN, name, driving-license number, Passport number and so on. Two objects can be on passport number as well as name. Hence, rule to compare two person cannot be predefined, a developer has to decide the criteria.
Java has defines the Comparable and Comparator interface to achieve the same.

ITCuties - Comparable and Comparator Interfaces in Java

ITCuties – Comparable and Comparator Interfaces in Java

Comparable Interface

Now we see’d how to use Comparable interface what need to be remembered while implementing this interface. The comparable interface define only one method compareTo()

public interface Comparable<T>
	// Compares this object with the specified object for order.
	int compareTo(T o)
  • 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.
  • The natural ordering for a class C is said to be consistent with equals if and only if e1.compareTo(e2) == 0 has the same boolean value as e1.equals(e2) for every e1 and e2 of class C.

The Comparable interface is used by the Collections.sort() method and the java.util.Arrays.sort() method to sort Lists and arrays of objects, respectively.

How to implement

To implement Comparable, a class must implement a single method, compareTo(). Since you are implementing the compareTo() method in a class, you have this reference available. You can compare the current element with the passed Element and return an int value.

Rule for returning value from compareTo() method

return  1; //if current object > passed object
return  0; //if current object == passed object
return -1; //if current object < passed object

In case of integer, numeric order will follow and in case of Strings lexical order will follow. For user defined classes such as Person class, you need to find the order to compare objects such as names, passport number etc.

How to use Collections.sort method

Example CollectionSort.java

package com.sorting;

import java.util.ArrayList;
import java.util.Collections;
import java.util.List;

public class CollectionSort {

    public static void main(String[] JavaLatte) {
        //Array list creation
        List<String> listOfNames = new ArrayList<String>();
        listOfNames.add("Z");
        listOfNames.add("A");
        listOfNames.add("Y");
        listOfNames.add("C");
        listOfNames.add("Q");
        // Default natural order sorting
        Collections.sort(listOfNames);
        //printing
        System.out.println(listOfNames);
    }
}

Example Person.java

package com.sorting;

public class Person {

    private String ssn;
    private String passportNo;
    private String name;
    private String drivingLicenceNo;

    /**
     * Constructor
     *
     * @param ssn
     * @param passportNo
     * @param name
     * @param drivingLicenceNo
     */
    public Person(String ssn, String passportNo, String name, String drivingLicenceNo) {
        this.ssn = ssn;
        this.passportNo = passportNo;
        this.name = name;
        this.drivingLicenceNo = drivingLicenceNo;
    }

    /**
     * Default constructor
     */
    public Person() {
    }

    public String getDrivingLicenceNo() {
        return drivingLicenceNo;
    }

    public String getName() {
        return name;
    }

    public String getPassportNo() {
        return passportNo;
    }

    public String getSsn() {
        return ssn;
    }
}

To sort Person object, you need to implement Comparable interface (change the class) . In this class, we’ll sort on the basis of name of a person. So person class will become PersonComparable.java and to see the result, execute PersonComparableDemo.java

package com.sorting;

public class PersonComparable implements Comparable<PersonComparable> {

    private String ssn;
    private String passportNo;
    private String name;
    private String drivingLicenceNo;

    /**
     * Constructor
     *
     * @param ssn
     * @param passportNo
     * @param name
     * @param drivingLicenceNo
     */
    public PersonComparable(String ssn, String passportNo, String name, String drivingLicenceNo) {
        this.ssn = ssn;
        this.passportNo = passportNo;
        this.name = name;
        this.drivingLicenceNo = drivingLicenceNo;
    }

    public PersonComparable() {
    }

    public String getDrivingLicenceNo() {
        return drivingLicenceNo;
    }

    public String getName() {
        return name;
    }

    public String getPassportNo() {
        return passportNo;
    }

    public String getSsn() {
        return ssn;
    }

    // Name wise sorting
    public int compareTo(PersonComparable o) {
        return this.name.compareTo(o.getName());
    }
}
package com.sorting;

import java.util.Arrays;

public class PersonComparableDemo {

    public static void main(String[] JavaLatte) {
        //Array of PersonComparable class
        PersonComparable[] listofPerson = {new PersonComparable("SSN1", "PASS1", "Robert", "D1"),
            new PersonComparable("SSN2", "PASS2", "William", "D2"),
            new PersonComparable("SSN3", "PASS3", "Charlie", "D3")};

        //printing
        System.out.println("Before sorting");
        System.out.println(Arrays.toString(listofPerson));

        System.out.println("After sorting");
        //Sorting 
        Arrays.sort(listofPerson);

        //printing
        System.out.println(Arrays.toString(listofPerson));
    }
}

When you call the sort() method, it calls the compareTo() method to compare Person objects by their names. Since Person names are unique, it is a natural comparison order that works well.

But there are two drawback with Comparable interface. Suppose one wants two different views of the Person list, one by name and one by SSN !
But when you make a collection element comparable (by having it implement Comparable), you get only one chance to implement the compareTo() method. So what can you do?
The horrible way would be to use a flag variable. Another is you need to modified the code to implement Comparable interface.
If we see sort() method is overloaded to take something called a Comparator. Now we’ll how this will help in sorting on the basis of different criteria.

Comparator interface

The Comparator interface gives you the capability to sort a given collection any number of different ways.

  • The other handy thing about the Comparator interface is that you can use it to sort instances of any class – even classes you can’t modify – unlike the Comparable interface, which forces you to change the class whose instances you want to sort.
  • The Comparator interface is also very easy to implement, having only one method, compare().
 	
public interface Comparator<T>
int compare(T o1, T o2); // Compares its two arguments for order.
boolean equals(Object obj); // Indicates whether some other object is "equal to" this comparator.
  • A comparison function, which imposes a total ordering on some collection of objects. Comparators can be passed to a sort method (such as Collections.sort or Arrays.sort) to allow precise control over the sort order.
  • Comparators can also be used to control the order of certain data structures (such as sorted sets or sorted maps), or to provide an ordering for collections of objects that don’t have a natural ordering.
  • The ordering imposed by a comparator c on a set of elements S is said to be consistent with equals if and only if c.compare(e1, e2)==0 has the same boolean value as e1.equals(e2) for every e1 and e2 in S.

An element in a list can compare itself to another of its own type in only one way using its compareTo() method. But a Comparator is external to the element type you’re comparing-it’s a separate class. So you can make as many of these as you like!
Want to compare Person by name? Make a PersonNameComaparator. Sort by name? Make a PersonNameComparator.

Then all you need to do is call the overloaded sort() method that takes the List and the Comparator that will help the sort() method put things in order.

Rules to be remembered:

  • Invoking the one-argument sort(List o) method means the list element’s compareTo() method determines the order. So the elements in the list MUST Implement the Comparable Interface.
  • Invoking sort(List o, Comparator c) means the list element’s compareTo() method will NOT be called, and the Comparators compare() method will be used Instead. That means the elements in the list do NOT need to Implement the Comparable Interface.

Suppose we want to sort Person object on the basis of SSN, now we don’t need to change Person class, but we’ll create another class that sort the object of Person on the basis of SSN.
PersonSSNSorting.java sort the Person object on the basis of SSN.

package com.sorting;

import java.util.Comparator;

public class PersonSSNSorting implements Comparator<Person> {

    public int compare(Person o1, Person o2) {
        return o1.getSsn().compareTo(o2.getSsn());
    }

}

PersonSSNSortingDemo.java demonstrate the execution of sorting Person object.

package com.sorting;

import java.util.Arrays;

public class PersonSSNSortingDemo {

    public static void main(String[] JavaLatte) {
        Person[] listofPerson = {new Person("SSN8", "PASS1", "Robert", "D1"),
            new Person("SSA2", "PASS2", "William", "D2"),
            new Person("SSV3", "PASS3", "Charlie", "D3")};

        System.out.println("Before sort");
        System.out.println(Arrays.toString(listofPerson));

        Arrays.sort(listofPerson, new PersonSSNSorting());
        System.out.println(Arrays.toString(listofPerson));
    }

}

Similar way we can create another class to sort Person object on the basis of other attributes, for instance driving licence number PersonDriverSorting.java.

package com.sorting;

import java.util.Comparator;

public class PersonDriverSorting implements Comparator<Person> {

    public int compare(Person o1, Person o2) {
        return o1.getDrivingLicenceNo().compareTo(o2.getDrivingLicenceNo());
    }

}
package com.sorting;

import java.util.Arrays;

public class PersonDriverSortingDemo {

    public static void main(String[] JavaLatte) {
        Person[] listofPerson = {new Person("SSN8", "PASS1", "Robert", "D1"),
            new Person("SSA2", "PASS2", "William", "Z2"),
            new Person("SSV3", "PASS3", "Charlie", "A3")};

        //printing
        System.out.println("Before sort");
        System.out.println(Arrays.toString(listofPerson));

        //sorting
        Arrays.sort(listofPerson, new PersonDriverSorting());
        //printing
        System.out.println("After sort");
        System.out.println(Arrays.toString(listofPerson));
    }
}

Difference between Comparator and Comparable

From the above discussion, it is easy to identify the difference between these two interface.

  • The method in the Comparable interface is declared as int compareTo(ClassType type);
  • The method in the Comparator interface is declared as int compare(ClassType type1, ClassType type2);.
  • You must modify the class whose instances you want to sort in case of Comparable but you build a class separate from the class whose instances you want to sort in case of Comparator.
  • Comparable is used when the objects need to be compared in their natural order where as Comparator is used when the objects need to be compared in custom user-defined order.
  • You do not create a separate class just to implement the Comparable interface where as you create a separate class just to implement the Comparator interface.
  • For a given class type, you have only that class (and that class alone) implementing the Comparable interface. In case of Comparator, you can have many separate (i.e., independent) classes implementing the Comparator interface, with each class defining different ways to compare objects.

Download this sample code here.

One Response to "Comparable and Comparator Interfaces in Java"

  1. Aslam says:

    Nicely explained article. Good job.

    Reply

Leave a Reply

Want to join the discussion?
Feel free to contribute!

Leave a Reply

Your email address will not be published. Required fields are marked *


*

You may use these HTML tags and attributes: <a href="" title=""> <abbr title=""> <acronym title=""> <b> <blockquote cite=""> <cite> <code> <del datetime=""> <em> <i> <q cite=""> <strike> <strong>