Friday, February 28, 2014

Comparable and Comparator Interfaces in Java

In this post, we'll see why we need Comparable and Comparator Interfaces, how to use and when to use. We'll also look into the difference between between in terms of their requirement and use.

As their name suggest, Comparable and Comparator Interfaces are used to compare similar objects for example, while performing searching and sorting.
Assume that you have a container containing a list of Person object.Now, how you compare two Person objects? There are any number of comparable attributes, such as SSN, name, driving-license number, and so on. Two objects can be compared on SSN as well as person’s name; this depends on the context. Hence, the criterion to compare the Person objects cannot be predefined; a developer has to define this criterion. Java defines Comparable and Comparator interfaces to achieve the same.

Comparable Interface
The Comparable class has only one method compareTo(), which is declared as follows:
public interface Comparable<T>
int compareTo(T o) : Compares this object with the specified object for order.

  • 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. Note that null is not an instance of any class, and e.compareTo(null) should throw a NullPointerException even though e.equals(null) returns false.
  • Virtually all Java core classes that implement Comparable have natural orderings that are consistent with equals. One exception is java.math.BigDecimal, whose natural ordering equates BigDecimal objects with equal values and different precisions (such as 4.0 and 4.00).

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. 
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. What should the int value be? Well, here are the rules for returning the integer value:

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

When you compare integer with each other numeric order will be follow and in case of string lexicographic comparison will follow. For user-defined classes, you need to find the natural order in which you can compare the objects. For example, for a Student class, StudentId might be the natural order for comparing Student objects.

The sort() method uses compareTo() to determine how the List or object array should be sorted. Since you get to implement compareTo() for your own classes, you can use whatever weird criteria you prefer, to sort instances of your classes.

Example: In this example, we'll sort the object of Student class on the basis of ID and to sort user-defined object we need to implement Comparable interface

We have implemented the Comparable<Student> interface. When you call the sort() method, it calls the compareTo() method to compare Student objects by their IDs. Since Student IDs are unique, it is a natural comparison order that works well.
Note : It’s important to remember that when you override equals() you MUST take an argument of type Object, but that when you override compareTo() you should take an argument of the type you’re sorting.

We can sort the list, but...
There's a new problem - Suppose wants two different views of the Student list, one by song id and one by grade !
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 in the Song class, and then do an if test in comparator) and give a different result depending on whether the flag is set to use title or artist for the comparison.
But that's an awful and brittle solution, and there 's something much better. Something built into the API for just this purpose-when you want to Sort the same thing in more than one way.
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, e2)==0 has the same boolean value as e1.equals(e2) for every e1 and e2 in S

It is used to be two method in Java 7, but now there are many method in Comparator interface in Java 8. As per Java 8 This is a functional interface and can therefore be used as the assignment target for a lambda expression or method reference.

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 Student by id? Make a StudentIdComaparator. Sort by name? Make a StudentNameComparator.

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. The sort() method that takes a Comparator will use the Comparator instead of the element's own compareTo(} method, when it puts the elements in order. In other words, if your sort method gets a Comparator, it won't even call the compareTo() method of the elements in the list. The sort() method will instead invoke the compare() method on the Comparator.

So, the rules are:

  1. Invoking the one-argument sort(L1st 0) method means the list element'ss compareTo() method determines the order. So the elements in the list MUST Implement the Comparable Interface.
  2. Invoking sort(List 0, Comparator c)means the list elemenfs 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.
Example :

java.lang.Comparable java.util.Comparator
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);.
     negative if objOne < objTwo
     zero if objOne == objTwo
     positive if objOne > objTwo
Same as Comparable
You must modify the class whose instances you want to sort. You build a class separate from the class whose instances you want to sort.
Implemented frequently in the API by: String, Wrapper classes, Date, Calendar… Meant to be implemented to sort instances of third-party classes.
Used when the objects need to be compared in their natural order. Used when the objects need to be compared in custom user-defined order (other than the natural order).
You do not create a separate class just to implement the Comparable interface 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. You can have many separate (i.e., independent) classes implementing the Comparator interface, with each class defining different ways to compare objects.

If you know anyone who has started learning Java, why not help them out! Just share this post with them. 
Thanks for studying today!...

1 comment:

  1. Thanks good explaination....Here another blog also explained nice please go through this blog