Thursday, July 29, 2021

How to use Comparator and Comparable in Java? With example

Comparator and Comparable in Java Examples
The difference between Comparator and Comparable in Java is very popular Java interview question mostly asked in the telephonic rounds and writing code to sort objects using Comparable or Comparator is popular on the written test round of interviews. The question was this “How you will sort Employee object based on his EmployeeID and his name” and this involves the use of both Comparable as well as Comparator interface in Java. This post is my revision on Java fundamentals similar to what I did about the equals method in Java and some tips to override hashCode in Java. 

All of these methods are fundamentals in the Java programming language and correct understanding is a must for any Java developer. Comparators and comparable in Java are two interfaces that are used to implement sorting in Java. 

It’s often required to sort objects stored in any collection classes like ArrayList, HashSet, or in Array, and at that time we need to use either compare() or compareTo() method defined in java.util.Comparator and java.lang.Comparable


In this Java tutorial, we will see examples of  Comparator and Comparable to sort objects in Java and discuss some best practices around when to use Comparator interface, etc. Any way before moving ahead Let’s see some important differences between Comparable and Comparator in Java.


Comparator vs Comparable in Java

Difference between Comparator vs Comparable in JavaHere are some of the common differences, which is worth remembering to answer this question if asked during a telephonic or face to face interview:

1) Comparator in Java is defined in java.util package while Comparable interface in Java is defined in java.lang package, which very much says that Comparator should be used as a utility to sort objects which Comparable should be provided by default.

2) Comparator interface in Java has method public int compare (Object o1, Object o2) which returns a negative integer, zero or a positive integer as the first argument is less than, equal to, or greater than the second. While Comparable interface has method public int compareTo(Object o) which returns a negative integer, zero, or a positive integer as this object is less than, equal to, or greater than the specified object.


3) If you see the logical difference between these two is Comparator in Java compare two objects provided to him, while Comparable interface compares "this" reference with the object specified. I have shared a lot of tips on how to override compareTo() method and avoid some common mistakes programmer makes while implementing Comparable interface.

4) Comparable in Java is used to implement the natural ordering of objects. In Java API String, Date and wrapper classes implement a Comparable interface.Its always good practice to override compareTo() for value objects.

5) If any class implements Comparable interface in Java then collection of that object either List or Array can be sorted automatically by using  Collections.sort() or Arrays.sort() method and object will be sorted based on there natural order defined by CompareTo method.

6)Objects which implement Comparable in Java  can be used as keys in a SortedMap like TreeMap or elements in a SortedSet  for example TreeSet, without specifying any Comparator.

These were combination of some theoretical and practical differences between Comparator and Comparator interface in Java. It does help you to decide when to use Comparator vs Comparable but things will be more clear when we some best practices around using both of these interfaces. Now let’s see an example of Comparator in Java:

 

Example of using Comparator and Comparable in Java

So in summary, if you want to sort objects based on natural order then use Comparable in Java and if you want to sort on some other attribute of an object then use Comparator in Java. Now to understand these concepts lets see an example or real-life coding:


1) There is a class called Person, sort the Person based on person_id, which is primary key in the database

2) Sort the Person based on there name.

For a Person class, sorting based on person_id can be treated as natural order sorting and sorting based on name field can be implemented using Comparator interface. To sort based on person_id we need to implement compareTo() method.


public class Person implements Comparable {
    private int person_id;
    private String name;
   
    /**
     * Compare current person with specified person
     * return zero if person_id for both person is same
     * return negative if current person_id is less than specified one
     * return positive if specified person_id is greater than specified one
     */

    @Override
    public int compareTo(Object o) {

        Person p = (Person) o;
        return this.person_id - o.person_id ;
    }
    ….
}

Generally, you should not use the difference of integers to decide output of compareTo method as result of integer subtraction can overflow but if you are sure that both operands are positive then its one of the quickest way to compare two objects. See my post things to remember while overriding compareTo in Java for more tips on compareTo.

And for sorting based on person name we can implement compare(Object o1, Object o2) method of Java Comparator class.

/**
 * Comparator implementation which sorts Person objects on person_id field
 */

public class SortByPerson_ID implements Comparator{

    public int compare(Object o1, Object o2) {

        Person p1 = (Person) o;
        Person p2 = (Person) o;
        return p1.getPersonId() - p2.getPersonId();
    }
}

Similar guidelines applies while implementing compare() method as well and instead of using subtraction operator, its better to use logical operator to compare whether two integers are equal to, less than or greater than. You can write several types of Java Comparator based upon your need for example  reverseComparator , ANDComparator , ORComparator etc which will return negative or positive number based upon logical results. String in Java even provides an special comparator called CASE_INSENSITIVE_ORDER, to perform case insensitive comparison of String objects.



How to Compare String in Java
String is immutable in Java and one of the most used value class. For comparing String in Java we should not be worrying because String implements Comparable interface and provides a lexicographic implementation for CompareTo method which compare two strings based on contents of characters or you can say in lexical order. You just need to call String.compareTo(AnotherString) and Java will determine whether specified String is greater than , equal to or less than current object. See my post 4 example to compare String in Java for alternatives ways of comparing String.


How to Compare Dates in Java
Dates are represented by java.util.Date class in Java and like String,  Date also implements Comparable in Java so they will be automatically sorted based on their natural ordering if they got stored in any sorted collection like TreeSet or TreeMap. If you explicitly want to compare two dates in Java you can call Date.compareTo(AnotherDate) method in Java and it will tell whether the specified date is greater than , equal to or less than current String. See my post 3 ways to compare Dates in Java for more alternatives of comparing two dates.


When to use Comparator and Comparable in Java
At last let’s see some best practices and recommendation on when to use Comparator or Comparable in Java:

1) If there is a natural or default way of sorting Object already exist during the development of Class then use Comparable. This is intuitive and you are given the class name people should be able to guess it correctly like Strings are sorted chronically, Employee can be sorted by their Id etc. 

On the other hand, if an Object can be sorted on multiple ways and client is specifying on which parameter sorting should take place then use the Comparator interface. for example, Employee can again be sorted on name, salary or department and clients needs an API to do that. Comparator implementation can sort out this problem.

2) Some time you write code to sort objects of a class for which you are not the original author, or you don't have access to code. In these cases you can not implement Comparable and Comparator is only way to sort those objects.

3) Beware with the fact that How those objects will behave if stored in SorteSet or SortedMap like TreeSet and TreeMap. If an object doesn't implement Comparable then while putting them into SortedMap, always provided a corresponding Comparator which can provide sorting logic.

4) Order of comparison is very important while implementing the Comparable or Comparator interface. for example, if you are sorting objects based upon name then you can compare first name or last name on any order, so decide it judiciously. I have shared more detailed tips on compareTo in my post on how to implement CompareTo in Java.

5) Comparator has a distinct advantage of being self-descriptive for example if you are writing Comparator to compare two Employees based upon their salary then a name that comparator as SalaryComparator, on the other hand, compareTo()


Related Java Tutorial from Javarevisited Blog

37 comments :

Anonymous said...

following link contains a very detailed article on the Comparator and Comparable interfaces

http://java-espresso.blogspot.com/2011/06/comparable-and-comparator-interfaces.html

Anonymous said...

can you put syntax highlighter your code example are really not visible clearly. i am looking for example of using comparable interface but initially missed your code example for comparator and comparable completely due to same color.

Anonymous said...

is there any other alternative for sorting in Java than using Comparator or Comparable ? your example of comparator and comparable is ok but let me know if there are more alternatives of java sorting.

Anonymous said...

On consistency of CompareTo() and equals() you probably would like to add when you compare any instance with null ,compareTo() method of comparable interface in java throws NullPointerException while in case of equals(null)
it should return false and if your compareTo() is not consistent with equals then those object will behave strangely in case if they will be used as key on SortedMap or value on SortedSet effectively they violates general contact
for set and map interface in java which is defined in terms of equals method. though this problem will not arise if you provide explicit comparator to sorted collection. anyway good effort and your example of comparator and comparable is decent.

Anonymous said...

Another difference between Comparator and Comparable is Comparator is used to impose total ordering while Comparable is used to impose natural ordering .

Anonymous said...

quite a funny thing you written tutorial about Comparable and Comparator in java but didn't mentioned about Sorting in Java or how to sort a HashMap or HashSet in Java. Sorting is quite important and whole purpose of having Comparator and Comparable interface is to allow Sorting in Java.

Anonymous said...

Hi, Is there any limitation on implementing Comparator for a Class in Java ? Precisely how many Comparator I can have for a data class in Java, I know we can have only one comparable though.

Rajiv said...

I don't think there is any limit on having Comparator implementation in Java, as long as you need sorting based on any field which make sense, you can implement or write Comparator. Though One Class can only have one Comparable implementation and natural order Sorting should be done there.

Anonymous said...

Hi, How can I sort array in Java ? I have a big Array of size of 10K elements which can contain either String or int, how Can I sort Array with String or int in Java ? any code sample or example would be much appreciated.

Karo said...

Hello, just small note, to avoid any misunderstandings for anyone, nor class neither interface Array have sort() method. This method is coming from Arrays class.

Anonymous said...

This Question "What is difference between Comparator and comparable in Java" is recently asked to me in a Java interview, they also asked why do you need Comparable in Java if same purpose can be achieved by Comparator interface in Java ?

Anonymous said...

My annotation lib for implementing Comparable and Comparator:

public class Person implements Comparable {
private String firstName;
private String lastName;
private int age;
private char gentle;

@Override
@CompaProperties({ @CompaProperty(property = "lastName"),
@CompaProperty(property = "age", order = Order.DSC) })
public int compareTo(Person person) {
return Compamatic.doComparasion(this, person);
}
}


Click the link to see more examples.
http://code.google.com/p/compamatic/wiki/CompamaticByExamples

madhu said...

while writing d code to write customized logic in implementation class i got an excepton like "class,enum,interface expected"
how can i solve that problem?

Q.Sayeed said...

Hi,
i am not agree with the statement that "Comparable in Java is used to implement only natural ordering of object."

I think, you can do all type of possible ordering by using Comparable as much as by using Comparator. You didn't think like that.

Javin @ ArrayList vs LinkedList said...

Q. Sayeed, you are correct on that compareTo can be use to implement any kind of sorting order in Java but standard is to use Comparable to implement natural order sorting of Object, natural order means lexicographic for String, ascending or descending for numeric and dates etc. let me know if you have any other doubt of Comparator and Comparable.

Anonymous said...

Hi Javin,

Thanks for the nice article... but can you please give some examples on what exactly is natural ordering and situations which requires Comparator instead of Comparable in other words where it requires to use Comparator only?

Eric Jablow said...

In any case, your Person should implement Comparable<Person>, not the raw type Comparable.

Furthermore, using subtraction: a-b &lt 0, == 0, or > 0 to determine ordering is generally unreliable. It is possible for a < b but a - b > 0 because integer arithmetic in Java is modulo 2^32. Integer.MIN_VALUE < 1. However, Integer.MIN_VALUE - 1 == Integer_MAX_VALUE, as the subtraction overflows. Always use code like:

return a < b ? -1 : (a > b ? 1 : 0);

Even if it doesn't seem necessary, you will do the right thing when it is.

Javin @ CyclicBarrier Example Java said...

Hi Eric, Thanks for your comment, both of your suggestions are perfectly valid. In fact not using Integer arithmetic to decide comparison order is what I discussed in my post about overriding ComparTo method, but given its conciseness, you can use it if its guaranteed that both numbers are positive.

Unknown said...

Wrong example....
it is compile time error...

please override compareTo() method dont overload.

Javin @ JDBC Best practices said...

@Saga, Thanks to catch that bug, one of the most common mistake programmers make while overriding equals, compareTo and compare methods, which accept Object as argument. Hope I had used @Override annotation :). Anyway good catch.

Anonymous said...

In first example it looks like a bug.
return this.person_id - o.person_id;

It should be:
return this.person_id - p.person_id;

Unknown said...

the casting for comparator example should have

Person p1 = (Person) o1;
Person p2 = (Person) o2;

Anonymous said...

Hi Javin, thanks for your post.
But you did not give any scenario in which comparator must be used and comarable will not work or vice-versa. If both can be used in every scenario then why java has provided 2 interfaces resolving the same purpose.?

Javin @ ClassLoader in Java said...

Hi @Anonymous, I think I have given, particularly on When to use Comparator and Comparable in Java. Anyway, Since Comparable is used to defined natural order sorting, You can only sort object one way e.g. either by using id or by using name. Now if you want to sort Person object based on Age, Salary etc. You need to create various Comparator e.g. AgeComparator, SalaryComparator etc. You can create as many Comparator as you need but only one natural ordering via Comparable.

genex said...

there are some typos in your code
like:
// in compareTo
return this.person_id - o.person_id ; // it should be p.person_id

//in compare
Person p1 = (Person) o; // it should be (Person) o1;
Person p2 = (Person) o; // it should be (Person) o2

Unknown said...

I like the article. I already knew some of the basic differences but was looking for more holistic views on this. Now I can feel it. Thanks :) Keep posting more.

Anonymous said...

return this.person_id - o.person_id ; // this is wrong....

this should be like
return this.person_id - p.person_id ; //missing p

Anonymous said...

Is there any way to sort the objects in middle out fashion ,say person ids are 1,2,3,4,5 in order.I want to sort the order in the following way 3,4,2,5,1

Anonymous said...

public int compareTo(Object o) {
Person p = (Person) o;
return this.person_id - o.person_id ;
}
….
}

Wrong code

Vitaly Zdanevich said...

"
2) Some time you write code to sort object of a class for which you are not the original author, or you don't have access to code. In these cases you can not implement Comparable and Comparator is only way to sort those objects.
"

But how I can implement Comparator if i don't have access to code?

Anonymous said...

@Vitaly, It doesn't required you to have access of code, if you have classes e.g. inside JAR file, you can code your own comparator which can compare those classes. On the other hand, you can not do the same with Comparable interface, because the class itslef need to be changed to add "implements Comparable" , which will not be possible until you have source file.

Unknown said...

Importance of Comparator interface:

1. The sorting logic can be placed in separate class. So you can create different custom comparator to compare objects based on different attributes.e.g Sorting using id, name etc.

2. The Comaprator interface helps you to compare objects from third party API. you can create a custom comparator and pass it to Collections.sort() method.

http://javacracker.com/sorting-list-of-objects-using-comparator-interface-in-java/

Anonymous said...

Thank you for such important artical. Sorry to say, but it doesn't give the clear cut idea of when to use Comparator or Comparable.

Unknown said...

Hi Javin,

2. The Comaprator interface helps you to compare objects from third party API. you can create a custom comparator and pass it to Collections.sort() method.

For this point, can you please provide a coding example as i was asked to write this programme in an interview recently.





javin paul said...

@Unknown, suppose Order object is from third party library, in that case you don't have access to code but you have access to binary.

Suppose you want to compare Order by total value, you can write a Total comparator as follows

class TotalComparator implements Comparator{

public int compare(Order o1, Order o2){
return o1.getTotal() - o2.getTotal();

}

}

Unknown said...

Hi ,
I got some important points to note from this article !!
In the second example which is supposed to compare the person names why have you compared person ids in SortByPerson_ID class . Please clarify . This question is really bothering me .

Thanks

Unknown said...

This is the code second example which is supposed to compare the person names

public class SortByPerson_Name implements Comparator{

public int compare(Object o1, Object o2) {
Person p1 = (Person) o;
Person p2 = (Person) o;
return p1.getName().compareTo(p2.getName());
}
}

Post a Comment