Sunday, 15 May 2011

Implementing Comparator interface

Suppose we have already decided natural ordering of the object, but for some reason we have to compare 2 objects based on some other fields in it.

Eg. Take the case of employee. We have already written compareTo() method for it. By this we have decided its natural ordering. Now, if we need to sort using other fields of the employee, we’ll have to change the Employee class’s compareTo() method to use those fields. But then we’ll loose this empId based sorting mechanism. This is not a good alternative if we need to sort using different fields at different occasions. But no need to worry; Comparator is there to save us.

By writing a class that implements the java.util.Comparator interface, you can sort Employees using any field as you wish even without touching the Employee class itself; Employee class does not need to implement java.lang.Comparable or java.util.Comparator interface.

Contract of compare method

java.util.Comparator: int compare(Object o1, Objecto2)
This method compares o1 and o2 objects. Returned int value has the following meanings.

  1. positive – o1 is greater than o2
  2. zero – o1 equals to o2
  3. negative – o1 is less than o1

Example

Sorting by name field

Following EmpSortByName class is used to sort Employee instances according to the name field. In this class, inside the compare() method sorting mechanism is implemented. In compare() method we get two Employee instances and we have to return which object is greater.

public class EmpSortByName implements Comparator<Employee>{

public int compare(Employee o1, Employee o2) {
return o1.getName().compareTo(o2.getName());
}
}


Watch out: Here, String class’s compareTo() method is used in comparing the name fields (which are Strings).
Now to test this sorting mechanism, you must use the Collections.sort(List, Comparator) method instead of Collections.sort(List) method. Now change the TestEmployeeSort class as follows. See how the EmpSortByName comparator is used inside sort method.

Using the above Comparator for sorting:

import java.util.*;

public class TestEmployeeSort {

public static void main(String[] args) {

List coll = Util.getEmployees();
//Collections.sort(coll);
//use Comparator implementation
Collections.sort(coll, new EmpSortByName());
printList(coll);
}

private static void printList(List<Employee> list) {
System.out.println("EmpId\tName\tAge");
for (Employee e: list) {
System.out.println(e.getEmpId() + "\t" + e.getName() + "\t" + e.getAge());
}
}
}


Sorting by empID field


Even the ordering by empId (previously done using Comparable) can be implemented using Comparator; following class does that.

public class EmpSortByEmpId implements Comparator<Employee>{

public int compare(Employee o1, Employee o2) {
return o1.getEmpId() - o2.getEmpId();
}
}


Comparator vs Comparable interface


The primary use of comparators is to pass them to something that does sorting, either one of the explicit sort methods, or to a data structure than implicitly sorts (eg, TreeSet or TreeMap).


Comparators are not needed for arrays of primitive values, or arrays of collections of objects that have a natural ordering, eg, String, BigInteger, etc.

No comments:

Post a Comment