When to use Comparable and Comparator
Asked Answered
M

19

124

I have a list of objects I need to sort on a field, say Score. Without giving much thought I wrote a new class that implements Comparator, that does the task and it works.

Now looking back at this, I am wondering if I should have instead have the my class implement Comparable instead of creating a new class that implements Comparator. The score is the only field that the objects will be ordered on.

  1. What I have done acceptable as a practice?

  2. Is the right approach "First have the class implement Comparable (for the natural ordering) and if an alternative field comparison is required, then create a new class that implements Comparator" ?

  3. If (2) above is true, then does it mean that one should implement Comparator only after they have the class implement Comparable? (Assuming I own the original class).

Mauer answered 15/2, 2010 at 15:12 Comment(0)
S
84

I would say that an object should implement Comparable if that is the clear natural way to sort the class, and anyone would need to sort the class would generally want to do it that way.

If, however, the sorting was an unusual use of the class, or the sorting only makes sense for a specific use case, then a Comparator is a better option.

Put another way, given the class name, is it clear how a comparable would sort, or do you have to resort to reading the javadoc? If it is the latter, odds are every future sorting use case would require a comparator, at which point the implementation of comparable may slow down users of the class, not speed them up.

Spirited answered 15/2, 2010 at 15:18 Comment(6)
Can you please give a quick example?Declinature
this might be good example: gist.github.com/yclian/2627608 There is Version class that uses ComparableVersion. Version - provides with factory methods ComparableVersion supposed to be object (with no static methods) - provides an version that is able to be compare with another one. Responsibilities are separated.Delozier
you can refer java-journal.blogspot.in/2011/01/…Dulsea
Interviewer asked, why use Comparator when the same can be done with Comparable, and I was dumb :(Elfrieda
@aLearner link is deadUnripe
@Unripe use https for it.Dulsea
F
138

Use Comparable if you want to define a default (natural) ordering behaviour of the object in question, a common practice is to use a technical or natural (database?) identifier of the object for this.

Use Comparator if you want to define an external controllable ordering behaviour, this can override the default ordering behaviour.

See also:

Fiveandten answered 15/2, 2010 at 15:17 Comment(3)
That's a technical explanation, and as correct as they come, but it doesn't really say anything about best practices.Hyperpyrexia
it's telling when to use each - if that isn't a best practice, what is it?Theorize
"Does implementing Comparable mean that I'm defining the natural order ?" , this gave me the answer i was looking for. Thanks :)Bombe
S
84

I would say that an object should implement Comparable if that is the clear natural way to sort the class, and anyone would need to sort the class would generally want to do it that way.

If, however, the sorting was an unusual use of the class, or the sorting only makes sense for a specific use case, then a Comparator is a better option.

Put another way, given the class name, is it clear how a comparable would sort, or do you have to resort to reading the javadoc? If it is the latter, odds are every future sorting use case would require a comparator, at which point the implementation of comparable may slow down users of the class, not speed them up.

Spirited answered 15/2, 2010 at 15:18 Comment(6)
Can you please give a quick example?Declinature
this might be good example: gist.github.com/yclian/2627608 There is Version class that uses ComparableVersion. Version - provides with factory methods ComparableVersion supposed to be object (with no static methods) - provides an version that is able to be compare with another one. Responsibilities are separated.Delozier
you can refer java-journal.blogspot.in/2011/01/…Dulsea
Interviewer asked, why use Comparator when the same can be done with Comparable, and I was dumb :(Elfrieda
@aLearner link is deadUnripe
@Unripe use https for it.Dulsea
T
63

Use Comparable:

  • if the object is in your control.
  • if the comparing behaviour is the main comparing behaviour.

Use Comparator :

  • if the object is outside your control and you cannot make them implement Comparable.
  • when you want comparing behaviour different from the default (which is specified by Comparable) behaviour.
Theorize answered 15/2, 2010 at 15:21 Comment(0)
I
32

Comparable - java.lang.Comparable: int compareTo(Object o1)

A comparable object is capable of comparing itself with another object. The class itself must implements the java.lang.Comparable interface in order to be able to compare its instances.

  • Capable of comparing current object with the provided object.
  • By using this we can implement only one sort sequence based on the instances properties. EX: Person.id
  • Some of the Predefined Classes like String, Wrapper classes, Date, Calendar has implemented Comparable interface.

Comparator - java.util.Comparator: int compare(Object o1, Object o2)

A comparator object is capable of comparing two different objects. The class is not comparing its instances, but some other class’s instances. This comparator class must implement the java.util.Comparator interface.

  • Capable of comparing any two Objects of Same Type.
  • By using this we can implement many sort sequence and name each, based on the instances properties. EX: Person.id, Person.name, Person.age
  • We can implement Comparator interface to our Pre-defined classes for Customized sorting.

Example:

public class Employee implements Comparable<Employee> {

    private int id;
    private String name;
    private int age;
    private long salary;

    // Many sort sequences can be created with different names.
    public static Comparator<Employee> NameComparator = new Comparator<Employee>() {         
        @Override
        public int compare(Employee e1, Employee e2) {
            return e1.getName().compareTo(e2.getName());
        }
    };
    public static Comparator<Employee> idComparator = new Comparator<Employee>() {       
        @Override
        public int compare(Employee e1, Employee e2) {
            return Integer.valueOf(e1.getId()).compareTo(Integer.valueOf(e2.getId()));
        }
    };

    public Employee() { }
    public Employee(int id, String name, int age, long salary){
        this.id = id;
        this.name = name;
        this.age = age;
        this.salary = salary;
    }
    // setters and getters.

    // Only one sort sequence can be created with in the class.
    @Override
    public int compareTo(Employee e) {
    //return Integer.valueOf(this.id).compareTo(Integer.valueOf(e.id));
    //return Character.toString(this.name.charAt(0)).compareToIgnoreCase(Character.toString(e.name.charAt(0)));
        if (this.id > e.id) {
            return 1;
        }else if(this.id < e.id){
            return -1;
        }else {
            return Character.toString(this.name.charAt(0)).compareToIgnoreCase(Character.toString(e.name.charAt(0)));
        }

    }   

    public static void main(String[] args) {

        Employee e1 = new Employee(5, "Yash", 22, 1000);
        Employee e2 = new Employee(8, "Tharun", 24, 25000);

        List<Employee> list = new ArrayList<Employee>();
        list.add(e1);
        list.add(e2);
        Collections.sort(list); // call @compareTo(o1)
        Collections.sort(list, Employee.nameComparator); // call @compare (o1,o2)
        Collections.sort(list, Employee.idComparator); // call @compare (o1,o2)
    }
}
  • For customized sorting we go for comparator @compare(o1, o2) for other scenarios we go for comparable @compareTo(o1), with out changing code if we want to sort more than one field then we use comparator.

For Java 8 Lambda : Comparator refer to my post.

Itagaki answered 6/7, 2015 at 11:24 Comment(0)
B
13

Comparable should be used when you compare instances of the same class.

Comparator can be used to compare instances of different classes.

Comparable is implemented by the class which needs to define a natural ordering for its objects. For example, String implements Comparable.

In case a different sorting order is required, then, implement comparator and define its own way of comparing two instances.

Boyes answered 6/7, 2011 at 8:23 Comment(0)
E
13

If sorting of objects needs to be based on natural order then use Comparable whereas if your sorting needs to be done on attributes of different objects, then use Comparator in Java.

Main differences between Comparable and Comparator:

+------------------------------------------------------------------------------------+
¦               Comparable                ¦                Comparator                ¦
¦-----------------------------------------+------------------------------------------¦
¦ java.lang.Comparable                    ¦ java.util.Comparator                     ¦
¦-----------------------------------------+------------------------------------------¦
¦ int objOne.compareTo(objTwo)            ¦ int compare(objOne, objTwo)              ¦
¦-----------------------------------------+------------------------------------------¦
¦ Negative, if objOne < objTwo            ¦ Same as Comparable                       ¦
¦ Zero,  if objOne == objTwo              ¦                                          ¦
¦ Positive,  if objOne > objTwo           ¦                                          ¦
¦-----------------------------------------+------------------------------------------¦
¦ You must modify the class whose         ¦ You build a class separate from to sort. ¦
¦ instances you want to sort.             ¦ the class whose instances you want       ¦
¦-----------------------------------------+------------------------------------------¦
¦ Only one sort sequence can be created   ¦ Many sort sequences can be created       ¦
¦-----------------------------------------+------------------------------------------¦
¦ Implemented frequently in the API by:   ¦ Meant to be implemented to sort          ¦
¦ String, Wrapper classes, Date, Calendar ¦ instances of third-party classes.        ¦
+------------------------------------------------------------------------------------+
East answered 22/5, 2018 at 6:21 Comment(0)
F
10

Comparator does everything that comparable does, plus more.

| | Comparable | Comparator ._______________________________________________________________________________ Is used to allow Collections.sort to work | yes | yes Can compare multiple fields | yes | yes Lives inside the class you’re comparing and serves | | as a “default” way to compare | yes | yes Can live outside the class you’re comparing | no | yes Can have multiple instances with different method names | no | yes Input arguments can be a list of | just Object| Any type Can use enums | no | yes

I found the best approach to use comparators as anonymous classes as follows:

private static void sortAccountsByPriority(List<AccountRecord> accounts) {
    Collections.sort(accounts, new Comparator<AccountRecord>() {

        @Override
        public int compare(AccountRecord a1, AccountRecord a2) {
            return a1.getRank().compareTo(a2.getRank());
        }
    });
}

You can create multiple versions of such methods right inside the class you’re planning to sort. So you can have:

  • sortAccountsByPriority
  • sortAccountsByType
  • sortAccountsByPriorityAndType

    etc...

Now, you can use these sort methods anywhere and get code reuse. This gives me everything a comparable would, plus more ... so I don’t see any reason to use comparable at all.

Finagle answered 16/11, 2014 at 8:27 Comment(0)
H
8

I would say:

  • if the comparison is intuitive, then by all means implement Comparable
  • if it is unclear wether your comparison is intuitive, use a Comparator as it's more explicit and thus more clear for the poor soul who has to maintain the code
  • if there is more than one intuitive comparison possible I'd prefer a Comparator, possibly build by a factory method in the class to be compared.
  • if the comparison is special purpose, use Comparator
Hyperpyrexia answered 15/2, 2010 at 15:31 Comment(0)
D
7

The following points help you in deciding in which situations one should use Comparable and in which Comparator:

1) Code Availabilty

2) Single Versus Multiple Sorting Criteria

3) Arays.sort() and Collection.sort()

4) As keys in SortedMap and SortedSet

5) More Number of classes Versus flexibility

6) Interclass comparisions

7) Natural Order

For more detailed article you can refer When to use comparable and when to use comparator

Dulsea answered 26/7, 2015 at 2:41 Comment(1)
I wonder why no one is upvoting this answer. It's a really nice one. +1Otherdirected
B
5

If you need natural order sorting -- User Comparable IF you need Custom Order Sorting - Use Comparator

Example:

Class Employee{
private int id;
private String name;
private String department;
}

Natural order Sorting would be based on id because it would be unique and custom order sortin g would be name and department.

Refrences:
When should a class be Comparable and/or Comparator? http://javarevisited.blogspot.com/2011/06/comparator-and-comparable-in-java.html

Bren answered 12/10, 2011 at 10:2 Comment(0)
L
4
  • If at the moment of writing the class you have only one use case of sorting use Comparable.
  • Only when you have more than one strategy of sorting implement a Comparator.
Labarum answered 15/2, 2010 at 16:15 Comment(0)
O
3

There had been a similar question here: When should a class be Comparable and/or Comparator?

I would say the following: Implement Comparable for something like a natural ordering, e.g. based on an internal ID

Implement a Comparator if you have a more complex comparing algorithm, e.g. multiple fields and so on.

Ochs answered 15/2, 2010 at 15:17 Comment(2)
Ordering on multiple fields can be as good done with Comparable.Fiveandten
For difference between comparable and comparator you can refer java-journal.blogspot.in/2010/12/…Dulsea
A
2

Comparable:
Whenever we want to store only homogeneous elements and default natural sorting order required, we can go for class implementing comparable interface.

Comparator:
Whenever we want to store homogeneous and heterogeneous elements and we want to sort in default customized sorting order, we can go for comparator interface.

Affra answered 12/12, 2011 at 3:18 Comment(0)
D
0

If you own the class better go with Comparable. Generally Comparator is used if you dont own the class but you have to use it a TreeSet or TreeMap because Comparator can be passed as a parameter in the conctructor of TreeSet or TreeMap. You can see how to use Comparator and Comparable in http://preciselyconcise.com/java/collections/g_comparator.php

Dantzler answered 15/2, 2010 at 15:13 Comment(0)
F
0

My need was sort based on date.

So, I used Comparable and it worked easily for me.

public int compareTo(GoogleCalendarBean o) {
    // TODO Auto-generated method stub
    return eventdate.compareTo(o.getEventdate());
}

One restriction with Comparable is that they cannot used for Collections other than List.

Feinberg answered 29/10, 2012 at 8:0 Comment(0)
M
0

I have been asked sorting of a definite range of numbers in better than nlogn time in one of interview. (Not using Counting sort)

Implementing Comparable interface over an object allows implicit sorting algos to use overridden compareTo method to order sort elements and that would be linear time.

Mathilda answered 15/7, 2015 at 18:30 Comment(0)
D
0

Comparable is the default natural sorting order provided for numerical values are ascending and for strings are alphabetical order. for eg:

Treeset t=new Treeset();
t.add(2);
t.add(1);
System.out.println(t);//[1,2]

Comparator is the custom sorting order implemented in custom myComparator class by overriding a compare method for eg:

Treeset t=new Treeset(new myComparator());
t.add(55);
t.add(56);
class myComparator implements Comparator{
public int compare(Object o1,Object o2){
//Descending Logic
}
}
System.out.println(t);//[56,55]
Delative answered 13/9, 2018 at 16:18 Comment(0)
R
-1

Very simple approach is to assume that the entity class in question be represented in database and then in database table would you need index made up of fields of entity class? If answer is yes then implement comparable and use the index field(s) for natural sorting order. In all other cases use comparator.

Revis answered 12/10, 2011 at 5:58 Comment(0)
M
-2

My annotation lib for implementing Comparable and Comparator:

public class Person implements Comparable<Person> {         
    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

Maud answered 8/1, 2012 at 1:42 Comment(0)

© 2022 - 2024 — McMap. All rights reserved.