"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
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.
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With