Java Comparable vs Comparator
In Java, both Comparable and Comparator interfaces are used for sorting objects. The main difference between Comparable and Comparator is:
- Comparable: It is used to define the natural ordering of the objects within the class.
- Comparator: It is used to define custom sorting logic externally.
Difference Between Comparable and Comparator
The table below demonstrates the difference between comparable and comparator in Java.
Features | Comparable | Comparator |
---|---|---|
Definition | It defines natural ordering within the class. | It defines external or custom sorting logic. |
Method | compareTo() | compare() |
Implementation | It is implemented in the class. | It is implemented in a separate class. |
Sorting Criteria | Natural order sorting | Custom order sorting |
Usage | It is used for a single sorting order. | It is used for multiple sorting orders. |
Example of Comparable
In this example, we use the Comparable interface to sort Movies by their release year using compareTo() method.
// Java program to demonstrate Comparable interface
import java.util.ArrayList;
import java.util.Collections;
// Movie class implements Comparable
// interface to define default sorting
class Movie implements Comparable<Movie> {
private String name;
private double rating;
private int year;
// Constructor
public Movie(String name, double rating, int year) {
this.name = name;
this.rating = rating;
this.year = year;
}
// Implementation of the compareTo method
// for default sorting by year
public int compareTo(Movie m) {
// Sort movies in ascending
// order of year
return this.year - m.year;
}
// Getter methods
public String getName() {
return name;
}
public double getRating() {
return rating;
}
public int getYear() {
return year;
}
}
public class Geeks {
public static void main(String[] args) {
// Create a list of movies
ArrayList<Movie> l = new ArrayList<>();
l.add(new Movie("Star Wars", 8.7, 1977));
l.add(new Movie("Empire Strikes Back", 8.8, 1980));
l.add(new Movie("Return of the Jedi", 8.4, 1983));
// Sort movies using Comparable's
// compareTo method by year
Collections.sort(l);
// Display the sorted list of movies
System.out.println("Movies after sorting by year:");
for (Movie m : l) {
System.out.println(m.getName() + " " + m.getRating() + " " + m.getYear());
}
}
}
Output
Movies after sorting by year: Star Wars 8.7 1977 Empire Strikes Back 8.8 1980 Return of the Jedi 8.4 1983
Explanation: In the above example, the compareTo() method sorts the Movie objects by their release year, where it return negative if the current movie year is earlier, return positive if the current movie year is later and return zero if the year are same. The Collections.sort() method uses the compareTo() method to compare and sort the movies in ascending order.
Now, suppose we want to sort movies by their rating and names as well. When we make a collection element comparable (by having it implement Comparable), we get only one chance to implement the compareTo() method. The solution is using Comparator.
Example of Comparator
In this example, we use Comparator interface to define custom sorting logic to sort movies first by rating and then by name.
// Java program to demonstrate Comparator interface
import java.util.ArrayList;
import java.util.Collections;
import java.util.Comparator;
class Movie {
private String name;
private double rating;
private int year;
// Constructor to initialize movie details
public Movie(String name, double rating, int year) {
this.name = name;
this.rating = rating;
this.year = year;
}
// Getter methods
public String getN() {
return name;
}
public double getR() {
return rating;
}
public int getY() {
return year;
}
}
// Comparator to sort movies by rating
class Rating implements Comparator<Movie> {
public int compare(Movie m1, Movie m2) {
// Sort by rating in descending order
return Double.compare(m2.getR(), m1.getR());
}
}
// Comparator to sort movies by name
class NameCompare implements Comparator<Movie> {
public int compare(Movie m1, Movie m2) {
// Sort by name in alphabetical order
return m1.getN().compareTo(m2.getN());
}
}
// Main class
public class Geeks {
public static void main(String[] args) {
// Create a list of movies
ArrayList<Movie> m = new ArrayList<>();
m.add(new Movie("Force Awakens", 8.3, 2015));
m.add(new Movie("Star Wars", 8.7, 1977));
m.add(new Movie("Empire Strikes Back", 8.8, 1980));
// Sort movies by rating and display all
Collections.sort(m, new Rating());
System.out.println("Movies sorted by rating:");
for (Movie m1 : m) {
System.out.println(m1.getR() + " " + m1.getN() + " " + m1.getY());
}
// Sort movies by name and display all
Collections.sort(m, new NameCompare());
System.out.println("\nMovies sorted by name:");
for (Movie m1 : m) {
System.out.println(m1.getN() + " " + m1.getR() + " " + m1.getY());
}
}
}
Output
Movies sorted by rating: 8.8 Empire Strikes Back 1980 8.7 Star Wars 1977 8.3 Force Awakens 2015 Movies sorted by name: Empire Strikes Back 8.8 1980 Force Awakens 8.3 2015 Star Wars 8.7 1977
Explanation: In the above example, the Comparator interface is used to sort the movies first by rating and then by name. The Rating and NameCompare classes implement custom sorting logic. The Collections.sort() method uses these comparators to sort the list by multiple criteria.
Important Point:
Comparator is a functional interface. So, now the question is why comparator is a functional interface?
Answer: Java 8 introduced functional interface. These interfaces has only one abstract method. But comparator has two methods that are compare(T o1, T o2) and equals(Object obj). Here, only compare() is an abstract method. The equals() method is inherited from the Object class and is not considered abstract in the interface.