Java Comparator and Comparable
Comparator and Comparable are two interfaces that provide ways to compare objects to determine their ordering. They serve different purposes and understanding when and how to use them is essential, especially when working with custom object sorting.
Comparable Interface
The Comparable interface is used to define the natural ordering of objects of a class. A class that implements comparable is inherently comparable, meaning its instances can be compared with each other using the compareTo method.
- Single Sorting Sequence: By implementing
Comparable, a class can only define one way of comparing its objects. - compareTo Method: This method must be implemented, and it takes one parameter of the same type as the class implementing it. It returns:
- A negative integer if the current object is less than the object being compared.
- Zero if they are equal.
- A positive integer if the current object is greater than the object being compared.
public class Product implements Comparable<Product> {
private int id;
private String name;
private double price;
public Product(int id, String name, double price) {
this.id = id;
this.name = name;
this.price = price;
}
@Override
public int compareTo(Product other) {
return Double.compare(this.price, other.price); // Sorting by price
}
@Override
public String toString() {
return "Product{id=" + id + ", name='" + name + "', price=" + price + "}";
}
public static void main(String[] args) {
List<Product> products = new ArrayList<>();
products.add(new Product(1, "Laptop", 1200.00));
products.add(new Product(2, "Smartphone", 800.00));
products.add(new Product(3, "Tablet", 500.00));
Collections.sort(products); // Sorts by price because of compareTo implementation
products.forEach(System.out::println);
}
}Advantages:
- Simple and Clear: If a natural order exists for a class, implementing
Comparableis straightforward. - Less Boilerplate: You don’t need to create separate comparator classes.
Disadvantages:
- Single Sort Criteria: The class can only be sorted in one way (natural order). For different sorting logic, you must create multiple comparator classes.
Comparator Interface
The Comparator interface is used to define multiple ways of comparing two different objects. It is a functional interface, meaning it can be implemented using lambda expressions.
- Multiple Sorting Sequences: You can create different comparators for different sorting sequences.
- compare Method: The method to implement is
compare(T o1, T o2), which returns:
Get Ramesh Maharaddi’s stories in your inbox
Join Medium for free to get updates from this writer.
A negative integer if o1 is less than o2, Zero if they are equal and A positive integer if o1 is greater than o2.
import java.util.*;
public class Student {
private int rollNo;
private String name;
private int age;
public Student(int rollNo, String name, int age) {
this.rollNo = rollNo;
this.name = name;
this.age = age;
}
@Override
public String toString() {
return "Student{rollNo=" + rollNo + ", name='" + name + "', age=" + age + "}";
}
public static void main(String[] args) {
List<Student> students = new ArrayList<>();
students.add(new Student(101, "Alice", 22));
students.add(new Student(102, "Bob", 20));
students.add(new Student(103, "Charlie", 22));
students.add(new Student(104, "David", 21));
students.add(new Student(105, "Eve", 20));
// 1. Sorting by Name using Inline Lambda
students.sort((s1, s2) -> s1.name.compareTo(s2.name));
System.out.println("Sort by Name (Inline Lambda):");
students.forEach(System.out::println);
// 2. Sorting by Age using Inline Lambda
students.sort((s1, s2) -> Integer.compare(s1.age, s2.age));
System.out.println("\nSort by Age (Inline Lambda):");
students.forEach(System.out::println);
// 3. Sorting by Name and then by Age using Inline Lambda
students.sort((s1, s2) -> {
int nameComparison = s1.name.compareTo(s2.name);
if (nameComparison == 0) {
return Integer.compare(s1.age, s2.age); // If names are the same, sort by age
}
return nameComparison;
});
System.out.println("\nSort by Name and then by Age (Inline Lambda):");
students.forEach(System.out::println);
// 4. Sorting by Name using a Comparator
Comparator<Student> compareByName = Comparator.comparing(student -> student.name);
students.sort(compareByName);
System.out.println("\nSort by Name (Comparator):");
students.forEach(System.out::println);
// 5. Sorting by Age using a Comparator
Comparator<Student> compareByAge = Comparator.comparingInt(student -> student.age);
students.sort(compareByAge);
System.out.println("\nSort by Age (Comparator):");
students.forEach(System.out::println);
// 6. Sorting by Name and then by Age using a Comparator
Comparator<Student> compareByNameThenAge = Comparator
.comparing((Student student) -> student.name)
.thenComparingInt(student -> student.age);
students.sort(compareByNameThenAge);
System.out.println("\nSort by Name and then by Age (Comparator):");
students.forEach(System.out::println);
}
}Advantages:
- Flexibility: Multiple sorting criteria can be implemented without modifying the original class.
- Can Be Used for Classes Without Natural Order: Even if the class doesn’t have a natural order, you can define one or more comparator classes.
Disadvantages:
- More Boilerplate Code: You may end up writing more code if you need several different comparators.
- External Comparators: Comparators are external to the objects being compared, which might make the code harder to maintain in some cases.
When to Use What:
- Use
Comparableif: - There is a single natural order that is commonly used.
- The comparison logic is simple and won’t change over time.
- You want to enable sorting of a collection of objects in their natural order using methods like
Collections.sort()orArrays.sort()without needing to pass a comparator. - Use
Comparatorif: - You need to sort objects in different ways, such as by multiple fields (e.g., by name, then by price).
- The comparison logic could change, and you want to keep the comparison code separate from the class itself.
- You need to compare objects of a class that you don’t control or can’t modify (like classes from a library).
In conclusion, Comparable is for defining a natural, intrinsic order of objects, while Comparator is more flexible and allows you to define custom sorting logic as needed. Both are essential tools in the Java ecosystem for sorting and comparing objects.






