Showing posts with label compare(). Show all posts
Showing posts with label compare(). Show all posts

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.

Sunday, 1 May 2011

Difference between Comparable and Comparator Interface

Key Difference between Comparable and Comparator interface

The key difference between comparable and comparator interface is:

Comparable Interface Comparator Interface
The comparable interface should be used when the current object is to be compared to objects of its type only.
The comparator should be used when some external class is taking your class as a parameter for some comparison operation and it doesn't know how to compare the objects and expects you to give it. In this case you can't give your class as the comparator. It has to be some other class which implements comparator interface and does the comparison.

The above is what we will learn from the following discussion about the two interfaces.

Comparable Interface

Lets start with the comparable interface:
The comparable interface is present in java.lang package. This means that you need not import this interface when you are implementing this interface.
This interface has only one method which has the signature as:

public int compareTo(Object o);

As the name suggests you want this object to be compared to someone else. In Java syntax, the code is:

CompareClass cmp1 = new CompareClass();
CompareClass cmp2 = new CompareClass();
cmp1.compareTo(cmp2);


The best definition of this interface will be the one given in Java API which is reproduced here:
This interface imposes a total ordering on the objects of each class that implements it

Its all upto the implementor to decide how and which kind of objects will he be comparing with the Object for which compareTo method has been invoked. Some facts related to comparable interface are as follows:
1) The compareTo() method should return -ve,zero or +ve integer depending upon whether this object is less than,equal to or greater than the specified object
2) The value returned by compareTo() should be consistent with the value returned by equals() method of the same class. if not so, the class should explicitly state that.
3) Any comparison with null should throw NullPointerException
4)If the object of the classes which implement this interface can be used as keys in the SortedMap or SortedSet.
5)Lists and Arrays that implemet this interface can be sorted using the Collections.sort(List/Array) method without specifying any external comparator.
Example: Lets take the example of String class. Here is a sample code which will clear the compareTo method for you:

public class Test
{
public static void main(String[] args)
{
String str1 = "bar";
String str2 = "barfoo";

int compareResult = str1.compareTo(str2);
if (compareResult < 0){
System.out.println(str1 + "is less than" + str2);
}else if (result == 0){
System.out.println(str1 +"is equal to" + str2);
}else{
System.out.println(str1 +"is greater than" + str2);
}
}
}





In this example, we are comparing String objects with other String objects and the comparTo method resides within the String class itself.


Comparator Interface



Now lets see the comparator interface.
The Comparator interface is a part of util package and needs to explicitly imported.
The general contract that is true for comparable is also true for comparator interface which is restated here because of its importance.
The value returned by the compare method of the class implementing the comparator interface should also return the same value with equals() method. This is important because the SortedSet and SortedMap will behave strangely.
There are two methods specified in the comparator interface which have the signature as follows:


int compare(T o1, T o2);
boolean equals(Object obj);


The compare() method should return -ve,zero or +ve integer depending upon whether this object is less than,equal to or greater than the specified object


Example:


import java.util.*;
class Test{

private int prop1;
public void setProp1(int prop1){
this.prop1=prop1;
}

public int getProp1(){
return this.prop1;
}
}


class TestComparator implements Comparator{

public int compare(Object obj1, Object obj2){
int test1 = ( (Test) obj1).getProp1();
int test2 = ( (Test) obj2).getProp1();

if( test1 > test2 )
return 1;
else if( test1 < test2 )
return -1; else return 0;
}
}


So whats the distinguishing part between the comparable and comparator?
Well its the difference in terms of the method signature at code level.
But in terms of design level, there is a big difference and should not be overlooked.
The comparable interface should be used when the current object is to be compared to objects of its type only.
The comparator should be used when some external class is taking your class as a parameter for some comparison operation and it doesn't know how to compare the objects and expects you to give it. In this case you can't give your class as the comparator. It has to be some other class which implements comparator interface and does the comparison. A typical example of this is the Collections.sort(List l, Comparator c) method.