Java Comparable vs Comparator
Omar Ismail
Senior Software Engineer @ Digitinary | Java 8 Certified? | Spring & Spring Boot?????? | AWS? | Microservices ?? | RESTFul Apis & Integrations ?? FinTech ?? | Open Banking ?? | Digital Payments and Transformation??
Thanks TO:Java Development Journal
Comparable
public interface Comparable<T>
When a class implement?Comparable, the compareTo method of the class defines the “natural” ordering of that object. CompareTo method should follow general contracts, few of the examples are
Comparator
public Interface Comparator<T>
Comparator?provides a way to compare 2 objects and can compare objects in a way that might not align with the natural ordering.
One of the common examples is String, String is generally compared alphabetically,?” a”.compareTo(“b”)??would use alphabetical comparisons.If you want to compare based on the String length, writing custom Comparator is a preferred solution.
If you do not have control over the source code (?where you can not implement Comparable?), then use Comparator.Comparator is useful when you have multiple ways to compare an object (?e.g you can compare cars by brand and cc etc.).
Both seem to be different, but to summarise, there isn’t much difference.Both ends to similar means. Implement comparable for natural order, and write a comparator for other sorting or comparison needs.
Java Sorting Example(Comparable and Comparator)
In this article, we will cover?Java Sorting Example (Comparable and Comparator). Java Collection API provides a way to sort Array?and Lists?but it expects input from the developer. This article will try to give an example to use both?java.lang.Comparable?and?java.util.Comparator?to sort objects.
?
1. Sort an ArrayList
Collections API’s utility class Collections?provide a handy way to sort an ArrayList in a natural ordering provided all elements in the list must implement?the Comparable?interface.
public class SimpleSorting {
public static void main(String[] args) {
List<String> locationList = new ArrayList<String>();
locationList.add("California");
locationList.add("Texas");
locationList.add("Seattle");
locationList.add("New Delhi");
Collections.sort(locationList);
for (String location?: locationList) {
System.out.println("Location is: " + location);
}
}
}
Output
Location is: California
Location is: New Delhi
Location is: Seattle
Location is: Texas
Above example worked perfectly with Collections.Sort() as List defined in example was Lits<String> and java.lang.String implements the Comparable interface. With List contains custom objects, Collections.sort() will fail if the custom object does not implement the Comparable interface.
?
2. Sort?Object?using?Comparable
public class Person implements Comparable<Person> {
private String name;
private int age;
public Person(String name, int age) {
super();
this.name = name;
this.age = age;
}
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
public int getAge() {
return age;
}
public void setAge(int age) {
this.age = age;
}
public int compareTo(Person person) {
return this.age > person.age?? 1?: this.age < person.age?? -1?: 0;
}
}
To sort it, we will use Collections.sort() method
public class ComparableDemo {
public static void main(String[] args) {
List<Person> persons = new ArrayList<Person>();
persons.add(new Person("Umesh Awasthi", 35));
persons.add(new Person("Robert Hickle", 55));
persons.add(new Person("John Smith", 40));
persons.add(new Person("David", 23));
Collections.sort(persons);
for (Person person?: persons) {
System.out.println("Person is: " + person.getName());
}
}
}
Output is
Person is: David
Person is: Umesh Awasthi
Person is: John Smith
Person is: Robert Hickle
Pay close attention to Person class declaration?public class Person implements Comparable<Person>?which shows that Person class is a comparable if you remove?Comparable<Person> from your Person class and try?Collection.sort(persons)?, compile will give the following error
领英推荐
Error:(21, 20) java: no suitable method found for sort(java.util.List<com.umeshawasthi.tutorials.corejava.sorting.Person>)
method java.util.Collections.<T>sort(java.util.List<T>) is not applicable
(inferred type does not conform to upper bound(s)
inferred: com.umeshawasthi.tutorials.corejava.sorting.Person
upper bound(s): java.lang.Comparable<? super com.umeshawasthi.tutorials.corejava.sorting.Person>)
method java.util.Collections.<T>sort(java.util.List<T>,java.util.Comparator<? super T>) is not applicable
(cannot infer type-variable(s) T
(actual and formal argument lists differ in length))
As a developer, it’s out responsibility to pass the comparable?object to?Collections.sort()?method.
It’s up to you how you want to use the compareTo method and what will be your comparison?logic, I have used a simple logic to compare the age of the person but you can use any custom logic to in?compareTo()?method.
?
3. Sort?Object?using?Comparator
java.lang.Comparable interface provides only one way to compare this object with another one, what are the options in case we need to compare 2 objects to sort them correctly. How about sorting Person with a name or age??What if we want to?override the natural ordering? We need to create a Comparator for these requirements.
First and super short template is to provide a custom comparator while calling?Collections.sort()?method
public class ComparatorDemo {
public static void main(String[] args) {
List<Person> persons = new ArrayList<Person>();
persons.add(new Person("Umesh Awasthi", 35));
persons.add(new Person("Robert Hickle", 55));
persons.add(new Person("John Smith", 40));
persons.add(new Person("David", 23));
persons.add(new Person("David", 63));
Collections.sort(persons, new Comparator<Person>() {
public int compare(Person person, Person person1) {
int name = person.getName().compareTo(person1.getName());
if(name == 0){
return name;
}
return person.getAge() > person1.getAge()?? 1?: person.getAge() < person1.getAge()?? -1?: 0;
}
});
for (Person person?: persons) {
System.out.println("Person is: " + person.getName());
}
}
}
Output
Person is: David
Person is: Umesh Awasthi
Person is: John Smith
Person is: Robert Hickle
Person is: David
Check the output, the interesting part is David, which is first and last result of the output.Another efficient way is to?define the Comparators in the Contact itself to reuse them instead of recreating every time
public class ComparatorPerson {
private String name;
private int age;
public ComparatorPerson(String name, int age) {
super();
this.name = name;
this.age = age;
}
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
public int getAge() {
return age;
}
public void setAge(int age) {
this.age = age;
}
public static Comparator<ComparatorPerson> COMPARE_BY_NAME = new Comparator<ComparatorPerson>() {
public int compare(ComparatorPerson one, ComparatorPerson other) {
return one.name.compareTo(other.name);
}
};
public static Comparator<ComparatorPerson> COMPARE_BY_AGE = new Comparator<ComparatorPerson>() {
public int compare(ComparatorPerson one, ComparatorPerson other) {
return one.age > other.age?? 1?: one.age < other.age?? -1?: 0;
}
};
}
Comparator with multi options
public class MultiComparatorDemo {
public static void main(String[] args) {
List<ComparatorPerson> persons = new ArrayList<ComparatorPerson>();
persons.add(new ComparatorPerson("Umesh Awasthi", 35));
persons.add(new ComparatorPerson("Robert Hickle", 55));
persons.add(new ComparatorPerson("John Smith", 40));
persons.add(new ComparatorPerson("David", 23));
persons.add(new ComparatorPerson("David", 63));
Collections.sort(persons,ComparatorPerson.COMPARE_BY_AGE?);
for (ComparatorPerson person?: persons) {
System.out.println("Person Name Sorted by Age is: " + person.getName());
}
System.out.println("######################################################");
Collections.sort(persons,ComparatorPerson.COMPARE_BY_NAME?);
for (ComparatorPerson person?: persons) {
System.out.println("Person Name Sorted by Name is: " + person.getName());
}
}
}
Output
Person Name Sorted by Age is: David
Person Name Sorted by Age is: Umesh Awasthi
Person Name Sorted by Age is: John Smith
Person Name Sorted by Age is: Robert Hickle
Person Name Sorted by Age is: David
######################################################
Person Name Sorted by Name is: David
Person Name Sorted by Name is: David
Person Name Sorted by Name is: John Smith
Person Name Sorted by Name is: Robert Hickle
Person Name Sorted by Name is: Umesh Awasthi
?
4. Sort?Object?using?Java8
Java 8?added a new way of making Comparators that reduces the amount of code you have to write?Comparator.comparing. Java 8 streaming API provides neater approach. It’s always good to understand how?compareTo()?and?compare()?method work under the hood
public class Java8CompareExample {
public static void main(String[] args) {
List<Person> persons = new ArrayList<Person>();
persons.add(new Person("Umesh Awasthi", 35));
persons.add(new Person("Robert Hickle", 55));
persons.add(new Person("John Smith", 40));
persons.add(new Person("David", 23));
persons.add(new Person("David", 63));
persons.sort(Comparator.comparing(Person::getName).thenComparingInt(Person::getAge));
for (Person person?: persons) {
System.out.println("Person Name is: " + person.getName());
}
persons.sort(Comparator.comparingInt(Person::getAge).thenComparing(Person::getName));
for (Person person?: persons) {
System.out.println("Person Name is: " + person.getName());
}
}
}
In this article, we cover?Java Sorting Example (Comparable and Comparator) provided by JDK, we will cover other API which provides the same functionalities with additional features. All the code of this article is available?Over on Github. This is a Maven-based project. As a bonus, have a look at?Apache Common ComparatorUtils?which provide some ready-to-use a feature for you.
?
To summarize, if sorting of objects needs to be based on natural order then use Comparable whereas if you sorting needs to be done on attributes of different objects, then use Comparator in Java.
Reference