Wednesday, 21 October 2015

Difference between Comparable and Comparator

While sorting elements in collection comparable and comparator interfaces come into picture which are used to sort collection elements. A natural question which comes to mind is why two different interfaces?

So in this post I'll try to explain the difference between comparable and comparator interfaces and why both of them are required. Before going into the differences between these two, let's have a brief introduction of both.

  • Comparable interface: Class whose objects are to be sorted implements this interface. The ordering imposed by the implementation of this interface is referred to as the class's natural ordering, and the class's compareTo method is referred to as its natural comparison method. Classes implementing 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 (like TreeMap) or as elements in a sorted set (like TreeSet), without the need to specify a comparator.

    General form of Comparable interface -

    public interface Comparable<T> {
     public int compareTo(T o);
    }
    
  • Comparator interface: In the case of Comparator, class that is to be sorted doesn't implement it. Comparator can be implemented by some other class, as an anonymous class or as lambda expression (from Java 8). 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).

    General form of Comparator interface -

    @FunctionalInterface
    public interface Comparator<T> {
      int compare(T o1, T o2);
    }
    

Note the annotation @FunctionalInterface, it's available from Java 8 and Comparator being a functional interface can be implemented using lambda expression.

Also note that apart from compare method which is the single abstract method there are several other default and static methods too with in the Comparator interface.

Java Example code

Let's see an example to further clarify when do we need comparable and when Comparator is needed.

Let's say we have an Employee class. Objects of this Employee class are stored in an array list and we want to sort it first on first name and then on last name. So this order is the natural order for the Employee class, employees are first sorted on first name and then last name.

Employee class

public class Employee implements Comparable<Employee>  {
    private String lastName;
    private String firstName;
    private String empId;
    private int age;
    public String getLastName() {
        return lastName;
    }
    public void setLastName(String lastName) {
        this.lastName = lastName;
    }
    public String getFirstName() {
        return firstName;
    }
    public void setFirstName(String firstName) {
        this.firstName = firstName;
    }
    public String getEmpId() {
        return empId;
    }
    public void setEmpId(String empId) {
        this.empId = empId;
    }
    public int getAge() {
        return age;
    }
    public void setAge(int age) {
        this.age = age;
    }
    
    @Override
    public String toString() {
        
        return getFirstName() + " " + getLastName() + " " + getAge() + " " + getEmpId();
    }
    @Override
    public int compareTo(Employee o) {
        int firstCmp = this.getFirstName().compareTo(o.getFirstName());
        return firstCmp != 0 ? firstCmp :  this.getLastName().compareTo(o.getLastName());
    }
}

Here note that Employee class is implementing Comparable interface providing implementation for the compareTo() method.

Class where sorting of the list will be done

public class SortObjectList {
    public static void main(String[] args) {
        List<Employee> empList = new ArrayList<Employee>();
        // Storing elements in the arraylist
        empList.add(getData("E001", "Mishra", "Pyaremohan", 35));
        empList.add(getData("E002", "Smith", "John", 45));
        empList.add(getData("E003", "Sharma", "Ram", 23));
        empList.add(getData("E004", "Mishra", "Pyaremohan", 60));
        empList.add(getData("E005", "Caroll", "Eva", 32));
        empList.add(getData("E003", "Tiwari", "Ram", 23));
        
        System.out.println("Original List");
        for(Employee emp : empList){
            System.out.println("" + emp);
        }
        // Sorting the list
        Collections.sort(empList);
        
        System.out.println("Sorted List");
        for(Employee emp : empList){
            System.out.println("" + emp);
        }    
    }
                
    // Stub method 
    private static Employee getData(String empId, String lastName, String firstName, int age){
        Employee employee = new Employee();
        employee.setEmpId(empId);
        employee.setLastName(lastName);
        employee.setFirstName(firstName);
        employee.setAge(age);
        return employee;
    }    
}

Output

Original List
Pyaremohan Mishra 35 E001
John Smith 45 E002
Ram Sharma 23 E003
Pyaremohan Mishra 60 E004
Eva Caroll 32 E005
Ram Tiwari 23 E003
Sorted List
Eva Caroll 32 E005
John Smith 45 E002
Pyaremohan Mishra 35 E001
Pyaremohan Mishra 60 E004
Ram Sharma 23 E003
Ram Tiwari 23 E003

When do we need Comparator

Now in case we want to sort in an order where, if names are same, they are sorted on the basis of age in descending order we can't use the already implemented compareTo() method of the Employee class. So you can say that if we want any ordering other than the defined natural ordering for the class then we have to use Comparator. In that case Comparator will provide an object that encapsulates an ordering.

Sorting logic

public class SortObjectList {
    public static void main(String[] args) {
        List<Employee> empList = new ArrayList<Employee>();
        // Storing elements in the arraylist
        empList.add(getData("E001", "Mishra", "Pyaremohan", 35));
        empList.add(getData("E002", "Smith", "John", 45));
        empList.add(getData("E003", "Sharma", "Ram", 23));
        empList.add(getData("E004", "Mishra", "Pyaremohan", 60));
        empList.add(getData("E005", "Caroll", "Eva", 32));
        empList.add(getData("E003", "Tiwari", "Ram", 23));
        
        System.out.println("Original List");
        for(Employee emp : empList){
            System.out.println("" + emp);
        }
        // Sorting the list
        Collections.sort(empList, new MyComparator());
                
        System.out.println("Sorted List");
        for(Employee emp : empList){
            System.out.println("" + emp);
        }    
    }
                
    // Stub method 
    private static Employee getData(String empId, String lastName, String firstName, int age){
        Employee employee = new Employee();
        employee.setEmpId(empId);
        employee.setLastName(lastName);
        employee.setFirstName(firstName);
        employee.setAge(age);
        return employee;
    }
    
    
}

class MyComparator implements Comparator<Employee>{
    @Override
    public int compare(Employee o1, Employee o2) {
        int firstCmp = o1.getFirstName().compareTo(o2.getFirstName());
        if(firstCmp == 0){
            int lastCmp = o1.getLastName().compareTo(o2.getLastName());
            if(lastCmp == 0){
                return (o2.getAge() < o1.getAge() ? -1 :
                       (o2.getAge() == o1.getAge() ? 0 : 1));
            }else{
                return lastCmp;
            }
            
        }else{
            return firstCmp;
        }        
    }    
}

Output

Original List
Pyaremohan Mishra 35 E001
John Smith 45 E002
Ram Sharma 23 E003
Pyaremohan Mishra 60 E004
Eva Caroll 32 E005
Ram Tiwari 23 E003
Sorted List
Eva Caroll 32 E005
John Smith 45 E002
Pyaremohan Mishra 60 E004
Pyaremohan Mishra 35 E001
Ram Sharma 23 E003
Ram Tiwari 23 E003

Here it can be seen that the name which is same is sorted by age in descending order.
Note here that a Comparator class MyComparator is implementing the Comparator interface and providing implementation for the compare() method. Also note that in Collections.sort method now we need to provide the Comparator class.

Collections.sort(empList, new MyComparator());

Comparator class can also be implemented as an Anonymous class or as a Lambda expression.

I hope now it is clear why two interfaces are provided for sorting and how they are used. So let's see the difference now -

Comparable Comparator
Comparable interface is in java.lang package. Comparator interface is in java.util package.
Comparable interface provides public int compareTo(T o); method which needs to be implemented for sorting the elements.
This method compares this object with object o and returns an integer, if that integer is -
  • Positive - this object is greater than o.
  • Zero - this object is equal to o.
  • Negative - this object is less than o.
Comparator interface provides int compare(T o1, T o2); method which needs to be implemented for sorting the elements. Here o1 and o2 objects are compared and an integer value is returned, if that integer is -
  • Positive - o1 is greater than o2.
  • Zero - o1 is equal to o2.
  • Negative - o1 is less than o2.
The class which has to be sorted should implement the comparable interface (sorting logic is in the class which has to be sorted), and that implementation becomes the natural ordering of the class. Some other class can implement the Comparator interface not the actual class whose objects are to be sorted. That way there may be many comparators and depending on the ordering needed specific comparator can be used. As example for Employee class if different orderings are needed based on first name, last name, age etc. then we can have different comparators with the implementations for those orderings.
To sort the list when Comparable is used we can use Collections.sort(List). To sort the list when Comparator is used, Comparator class has to be explicitly specified as a param in the sort method. Collections.sort(List, Comparator)

That's all for this topic Difference between comparable and comparator. If you have any doubt or any suggestions to make please drop a comment. Thanks!

Related Topics

  1. How to sort arraylist in Java
  2. How to sort arraylist of custom objects in Java
  3. How to sort an ArrayList in descending order
  4. How to Sort elements in different order in TreeSet using Comparator
  5. Java Collections interview questions

You may also like -

No comments:

Post a Comment