Reputation: 31252
"How will you sort collection of employee objects by its id or name". For that we can use two interfaces, i.e., Comparator and Comparable.
seems this is one of the common interview questions
But I don't see a reason why I should use both for sorting employee objects
I have been thinking on what comparator
accomplishes that Comparable
cannot do.
I understand that if the objects (instance variables that is compared upon) have natural ordering then comparable
is the right choice.
but if custom ordering is needed (eg string length) then one could write a comparator.
my point here is comparator
is only needed by the client if he wants to sort the data by some other criteria.
For example, I would implement an Employee class
to sort by id
using comparable interface
.
but if the client wants to sort Employee objects by String
(name), he would implement comparator
either as a concrete class or anonymously in sorting.
Is there anything I am missing here?
For example, In the following code, for the Person object, my compareTo method, compares the age and sort it In the compare method, I use String length (name of the person) for sorting. In theory, I could accomplish both in the compareTo method as I have implemented below.
lastly, are there any added benefits of one of the following over other I have implemented comparator in two ways 1. as a static method which is commented out 2. as anonymous object(?) in the main method which is commented out 3. make a new class that implements comparator and call the instance of that class in collections.sort() -- this I have not done here
(The commented-out parts of the code works. They are just different implementations)
mport java.util.Collections;
import java.util.Comparator;
import java.util.*;
public class PersonComparator implements Comparable{
private String name;
private int age;
public PersonComparator(String name, int age) {
this.name = name;
this.age = age;
}
@Override
public String toString() {
return "name=" + name + ", age=" + age;
}
/*@Override
public int compareTo(Object obj) {
if (!(obj instanceof PersonComparator)) {
throw new ClassCastException("Invalid object");
}
PersonComparator p2 = (PersonComparator)obj;
return this.age-p2.age;
}*/
/*Alternative CompareTo that checks for both age and name*/
public int compareTo(Object obj) {
if (!(obj instanceof PersonComparator)) {
throw new ClassCastException("Invalid object");
}
PersonComparator p2 = (PersonComparator)obj;
if (this.age!=p2.age){
return this.age-p2.age;
}
else {
return (this.name.length()-p2.name.length());
}
}
/*public static Comparator nameLengthComparator
= new Comparator() {
@Override
public int compare(Object obj1, Object obj2) {
if (!(obj1 instanceof PersonComparator) || !(obj2 instanceof PersonComparator)){
throw new ClassCastException("Invalid object");
}
else {
PersonComparator p1 = (PersonComparator)obj1;
PersonComparator p2 = (PersonComparator)obj2;
return p1.name.length()-p2.name.length();
}
}
};*/
public static void main(String[] args){
PersonComparator p1 = new PersonComparator("Alexander", 45);
PersonComparator p2 = new PersonComparator("Pat", 27);
PersonComparator p3 = new PersonComparator("Zacky", 45);
PersonComparator p4 = new PersonComparator("Rake", 34);
List<PersonComparator> list = new ArrayList<PersonComparator>();
list.add(p1);
list.add(p2);
list.add(p3);
list.add(p4);
System.out.println("Before sorting "+ list);
Collections.sort(list);
//System.out.println("After sorting by age "+ list);
//System.out.println("Before sorting "+ list);
//Collections.sort(list, nameLengthComparator);
System.out.println("After sorting by name length "+ list);
/*Collections.sort(list, new Comparator<PersonComparator>() {
@Override
public int compare(PersonComparator p1, PersonComparator p2) {
return p1.name.length()-p2.name.length();
}
}
);*/
System.out.println("After sorting by name length "+ list);
}
}
Thanks
Upvotes: 6
Views: 7429
Reputation: 10632
Comparable
interfaceThe Comparable
interface defines a type's natural ordering. Suppose you have a list of String
or Integer
objects; you can pass that list to
Collections.sort(list);
and you will have a sorted list. How? Because String
and Integer
both implement Comparable
interface and the implementations of Comparable
interface provide a natural ordering. Its like the class definition saying - "If you find a collection of objects of my type, order them according to the strategy I have defined in the compareTo
method".
Now when you define your own type, you can define the natural ordering of the objects of your class by implementing the Comparable
interface. See the Java documentation for more information on object ordering.
Comparator
interfaceThe Comparator
interface describes how to define custom strategies for object ordering. Suppose we have a simple Person
type as below:
public class Person {
String name;
public Person(String name) {
this.name = name;
}
public String getName() {
return name;
}
}
Now, by implementing the Comparator
interface, you can write different strategies to order the instances of your Person
type. For example, consider the two strategies for ordering Person
objects given below:
class StrategyOne implements Comparator<Person> {
@Override
public int compare(Person p1, Person p2) {
return p1.getName().length() - p2.getName().length();
}
}
class StrategyTwo implements Comparator<Person> {
@Override
public int compare(Person p1, Person p2) {
return p1.getName().compareTo(p2.getName());
}
}
Here, StrategyOne
will order Person
objects based on the length of their names, and StrategyTwo
will order Person
objects based on lexicographic ordering of their names.
Comparator
As you can see, the concrete strategy classes are stateless, hence all instances are functionally equivalent. So, we just need a single instance of any concrete strategy class. Thus, it should be a singleton. Using anonymous classes will create a new instance each time the call is executed. Consider storing the object in a private static final field and reusing it by using static factory methods to access them [Effective Java]. For example, you can reuse the above two concrete strategies as below:
class Strategies {
private static final Comparator<Person> PERSON_NAME_LENGTH_COMPARATOR = new StrategyOne();
private static final Comparator<Person> PERSON_NAME_LEXICAL_COMPARATOR = new StrategyTwo();
public static Comparator<Person> personNameLengthComparator(){
return PERSON_NAME_LENGTH_COMPARATOR;
}
public static Comparator<Person> personNameLexicalComparator(){
return PERSON_NAME_LEXICAL_COMPARATOR;
}
}
To summarize, the Comparable
interface is used to define the natural ordering of a class, and the Comparator
interface is used to define particular strategies for object ordering.
Upvotes: 10
Reputation: 233
If you are using comparator , you just need to add one comparator class and pass it to Collections.sort() method along with List object no other change in existing code.
but if you implement comparable interface you will have to change code of all the model/bean classes to override compareTo() method.
so for Loose Coupling comparator is better.
Upvotes: 0
Reputation: 8096
Here you go... I have already written a lot on this clarification aided with pictures and explanations.
Please find the link below:
One think you can always remember and that is "they can’t be used interchangeably"
Upvotes: 0
Reputation: 2274
Comparable allows you to sort items in a collections based on only one field.Comparator provides the flexibility to compare items based on more than one field
For example.
class Person implements Comparable
{
int age;
String name;
Person(int age,String name)
{
this.age=age;
this.name=name;
}
public int compareTo(Object o1) // Either you can compare according to age or name
{
Person p = (Person)o1;
if (this.age==p.age)
return 0;
else if (this.age>p.age)
return 1;
else
return -1;
}
public int compareTo(Object o) //Based on name comparision
{
return (this.name.compareTo((Person)o).name));
}
public static void main (String args[])
{
List<Person> list = new ArrayList<Person>();
Person o = new Person(12,"Steve");
Person o1 = new Person(13,"Jason");
list.add(o);
list.add(o1);
Collections.sort(list);
}
}
In case of Comparable above, you can sort items either using age or name.But in case of Comparator ,you can sort the items based on more than one field.
class AgeComparison implements Comparator
{
public int compare(Object o1,Object o2)
{
Person s1 = (Person)o1;
Person s2 =(Person)o2;
if (s1.age==s2.age)
return 0;
if(s1.age>s2.age)
return 1;
else
return -1;
}
class NameComparison implements Comparator
{
public int compare(Object o1,Object o2)
{
Person s1 = (Person)o1;
Person s2 =(Person)o2;
return (s1.age.compareTo(s2.age));
}
}
To use Comparator, you have to pass the list and the instance of class you have to use.
Collections.sort(list,new NameComparison());
Collections.sort(list,new AgeComparison());
In a nutshell, the advantage of Comparator is the flexibility to sort the list based on more than one field of the object.
Upvotes: 3
Reputation: 718788
In what way is a comparator superior to comparable?
It is not "superior". It is just that the two interfaces are doing (roughly) the same thing in different ways. In the Comparable
case the ordering logic is in the object being ordered. In the Comparator
case, the logic is in a different class from the objects being declared.
But I don't see a reason why I should use both for sorting employee objects
The only case where it would make sense to use both would be if you needed to be able to sort the objects into different orders. Then you could declare the relevant classes as implementing Comparable
for the "natural" order and use Comparator
objects to implement the other orders.
By the way, a comparator probably should not implement Comparable
, and vice versa.
If a comparator implements Comparable
that implies you are trying to order instances of the comparator object itself ...
Your PersonComparator
class is misnamed. It should really be called Person
.
Could you clarify one thing in your answer that we have already
equals()
method from Object class then why theComparator
interface is facilitating theequals()
method again?
A number of points:
You still seem to be confusing the purpose of Comparable
and Comparator
. The equals
method on a Comparator
object compares the comparator with other comparators!!
The equals
method tells you whether two objects are equal ... not which one comes first.
The reason that Comparator
overrides equals
is solely so that they can clearly document what equals(Object)
does when you call it on a Comparator
object. (The actual behaviour is entirely consistent with Object.equals(Object)
... but they obviously thought it necessary to do this because programmers were repeatedly getting the semantics of the method wrong.)
Upvotes: 8
Reputation: 13556
In what way is a comparator superior to comparable?
I won't say it is superior but one advantage is that it enables us to write multiple sort sequences. In case of Comparable
, you would have to implement that interface by your class which you want to sort and you can write only one sort sequence.
With Comparator
, you can make different classes for sort sequences and while sorting, you just pass the Comparator
instance to COllections.sort()
method.
Consider Employee
class which has fields id
, firstName
and lastName
. If you implement Comparable
, you can write only one sorting logic in compareTo
method.
If you implement Comparator
then you can create separate sorting sequences by creating separate classes. e.g. IdSorter
, FirstNameSorter
and LastNameSorter
which gives you way to sort Employee
in multiple ways.
Read
Sorting user defined objects with Comparator
Upvotes: 4
Reputation: 15729
In general, use Comparable when the ordering is "obvious". E.g., for Strings you use alphabetical, for numbers you use numeric order. Note that a Comparable object can only implement a single compareTo() method, so you only get one option - the "natural", "obvious" option. The advantage is that it is simple and client code doesn't have to do any extra work to compare things.
Use Comparator if the ordering is less obvious, or you might want to have multiple options. For example, a Book might get sorted by Title, Author, ISBN, etc. You could have three different Comparators to handle those three cases. You might want to sort Strings by some unusual order, e.g. a special case for a foreign language, ignoring capitals, etc.
Also, if the Objects you are sorting do not implement Comparable, or you are mixing types that do not like to compare to each other (in general, this is to be avoided, but perhaps you want to be able to compare Books and Authors in a single list in some special case) you need to use Comparator.
Upvotes: 0