Friday, September 21, 2012

Java Comparable vs Comparator interface



Let us see the basic interfaces and its methods:

public interface java.lang.Comparable{
    public abstract int compareTo(java.lang.Object);
}


public interface java.util.Comparator{
    public abstract int compare(java.lang.Object, java.lang.Object);
    public abstract boolean equals(java.lang.Object);
}


Let us observe the following code :

            Here i am trying to sort some group of stirng objects using Arrays.sort() method and collections.sort() method respectively it sorted and gave me the proper output ....but when i tried to sort group of employee objects i got the exception as :Exception in thread "main" java.lang.ClassCastException: Employee cannot be cast to java.lang.Comparable

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


public class Test {

            public static void main(String[] args) {
                       
                        String names []={"Apple","Avacado","Apricot","Grapes","Gooseberries"};
                       
                        Arrays.sort(names);
                        System.out.println("Using Arrays.sort()");
                        for (String lString : names) {
                                    System.out.println("Fruit :"+lString);
                        }
                       
                        List fruits = new ArrayList();
                        for (String lString : names) {
                                    fruits.add(lString);
                        }
                       
                        Collections.sort(fruits);
                        System.out.println("Using Collections.sort()");
                        for (String lString : fruits) {
                                    System.out.println("Fruit :"+lString);
                        }
                       
                       
                        Employee emp[] = new Employee[5];
                       
                        emp[0] = new Employee("R001", "Robin", 45000);
                        emp[1] = new Employee("R012", "Antony", 55000);
                        emp[2] = new Employee("R011", "Williams", 75000);
                        emp[3] = new Employee("R121", "John", 65000);
                        emp[4] = new Employee("R061", "James", 35000);

                       
                        Arrays.sort(emp);
                       
                        for(Employee e:emp){
                                  
                                    System.out.println("Employee :id :"+e.getEmpId()+" \t Name :"+e.getEmpName()+"\t sal :"+e.getEmpSal());
                                   
                        }
            }
}


Output:

Using Arrays.sort()
Fruit :Apple
Fruit :Apricot
Fruit :Avacado
Fruit :Gooseberries
Fruit :Grapes

Using Collections.sort()
Fruit :Apple
Fruit :Apricot
Fruit :Avacado
Fruit :Gooseberries
Fruit :Grapes

Exception in thread "main" java.lang.ClassCastException: Employee cannot be cast to java.lang.Comparable
            at java.util.Arrays.mergeSort(Unknown Source)
            at java.util.Arrays.sort(Unknown Source)
            at Test.main(Test.java:40)


When trying to sort Employee objects the error because Arrays.sort()

See the method :

 public static void sort(java.lang.Object[]);

     All elements in the array must implement the Comparable interface.Then only it can do natural ordering of elements.
So i changed my Employee class as below :

import java.util.Comparator;

public class Employee implements Comparable {

      private String mEmpId;
      private String mEmpName;
      private double mEmpSal;

      public Employee(String pEmpId, String pEmpName, double pEmpSal) {
            super();
            mEmpId = pEmpId;
            mEmpName = pEmpName;
            mEmpSal = pEmpSal;
      }

      public String getEmpId() {
            return mEmpId;
      }

      public void setEmpId(String pEmpId) {
            mEmpId = pEmpId;
      }

      public String getEmpName() {
            return mEmpName;
      }

      public void setEmpName(String pEmpName) {
            mEmpName = pEmpName;
      }

      public double getEmpSal() {
            return mEmpSal;
      }

      public void setEmpSal(double pEmpSal) {
            mEmpSal = pEmpSal;
      }

      @Override
      public int compareTo(Employee empObj) {
            double empSal = empObj.getEmpSal();
            return empSal > mEmpSal ? 0 : 1;
      }
      /*
       * This is to compare based on empName
       */
      public static Comparator EmployeeNameComparator = new Comparator() {

            @Override
            public int compare(Employee e1, Employee e2) {
                return e1.getEmpName().compareTo(e2.getEmpName());
            }

      };
      /*
       * This is to compare based on employee id
       */
      public static Comparator EmployeeIdComparator = new Comparator() {

            @Override
            public int compare(Employee e1, Employee e2) {

                  return e1.getEmpId().compareTo(e2.getEmpId());
            }

      };
}



Here with this class you can observe i have implemented method
             public abstract int compareTo(java.lang.Object);

            This method will automatically have current object and then gets the next object to compare.
This method i have overriden to sort employee based on their salary.


Now coming to Comparator interface you can observe
             public abstract int compare(java.lang.Object, java.lang.Object);

            It takes two arguments obj1,obj2.

When ever you want to add any other sorting techniques for your custom objects you can use this.

Here in my class i have created two anonymous classes to sort employee objects based on their name and employeeId.

           

import java.util.Arrays;


public class EmpMain {
     
            public static void main(String[] args) {
            Employee emp[] = new Employee[5];
                 
            emp[0] = new Employee("R001", "Robin", 45000);
            emp[1] = new Employee("R012", "Antony", 55000);
            emp[2] = new Employee("R011", "Williams", 75000);
            emp[3] = new Employee("R121", "John", 65000);
            emp[4] = new Employee("R061", "James", 35000);

           Arrays.sort(emp);
           System.out.println("Without any comparator : ");
           for(Employee e:emp){
                    
             System.out.println("Employee :id :"+e.getEmpId()+" \t Name :"+e.getEmpName()+"\t sal :"+e.getEmpSal());
                       
                  }
                 
            Arrays.sort(emp,Employee.EmployeeIdComparator);
                 
            System.out.println("With empId comparator : ");
            for(Employee e:emp){
            System.out.println("Employee :id :"+e.getEmpId()+" \t Name :"+e.getEmpName()+"\t sal :"+e.getEmpSal());
                       
                  }
                 
            }
}

Without any comparator :
Employee :id :R061       Name :James      sal :35000.0
Employee :id :R001       Name :Robin      sal :45000.0
Employee :id :R012       Name :Antony     sal :55000.0
Employee :id :R121       Name :John sal :65000.0
Employee :id :R011       Name :Williams   sal :75000.0
With empId comparator :
Employee :id :R001       Name :Robin      sal :45000.0
Employee :id :R011       Name :Williams   sal :75000.0
Employee :id :R012       Name :Antony     sal :55000.0
Employee :id :R061       Name :James      sal :35000.0
Employee :id :R121       Name :John sal :65000.0

This also u can use :


List empList = new ArrayList();
                  empList.add(emp[0]);
                  empList.add(emp[1]);
                  empList.add(emp[2]);
                  empList.add(emp[3]);
                  empList.add(emp[4]);
                 
                 
                  Collections.sort(empList);
                 
                  for (Employee lEmployee : empList) {
                        System.out.println("Employee :id                              :"+lEmployee.getEmpId()+" \t Name :"+lEmployee.getEmpName()+"\t sal :"+lEmployee.getEmpSal());
                  }
           

Collections.sort(empList,Employee.EmployeeNameComparator);
                 
                  for (Employee lEmployee : empList) {
                        System.out.println("Employee :id :"+lEmployee.getEmpId()+" \t Name :"+lEmployee.getEmpName()+"\t sal :"+lEmployee.getEmpSal());
                  }
                       
Conclusion :

Use Comparable for natural sort ordering and use Comparator for any custom sorting .....


Always Arrays.sort() and Collections.sort() can sort only objects of type comparable.