Learn the difference between Comparable and Comparator in Java with simple examples, use cases, and best practices to master custom object sorting.
🏁 Introduction
Imagine you’re sorting a list of your favorite movies — maybe by their release year, rating, or title. Depending on what you choose, the order changes! In Java, we often face similar situations when sorting objects like students, employees, or products.
That’s where Comparable and Comparator come into play. These two interfaces in Java help you define custom sorting logic for your objects — whether it’s sorting names alphabetically, marks in descending order, or prices from low to high.
In this article, we’ll clearly explain the difference between Comparable and Comparator, walk through practical examples, and share best practices to help you avoid common pitfalls.
💡 Core Concepts
🔹 Comparable — Natural Ordering
The Comparable interface defines a default or natural ordering for the objects of a class.
It belongs to the java.lang package and contains a single method:
int compareTo(T obj);
When a class implements Comparable, it decides how its objects should be compared — like how strings are alphabetically ordered by default.
Key Points:
- Used to define natural order of objects (e.g., alphabetical, ascending order).
- Implemented inside the class being sorted.
- Used by methods like
Collections.sort()orArrays.sort(). - Allows only one sorting logic per class.
Example: Students sorted by their roll numbers.
🔹 Comparator — Custom or External Ordering
The Comparator interface, on the other hand, allows you to define multiple sorting strategies outside the class.
It belongs to the java.util package and defines the method:
int compare(T obj1, T obj2);
You can use different comparators for different sorting needs — for example, one for sorting by name, another by marks.
Key Points:
- Used to define custom or multiple orderings.
- Implemented outside the class being sorted.
- Often used with
Collections.sort()orList.sort(). - Can be implemented using lambda expressions (Java 8+).
Think of Comparable as a default sorting rule (like alphabetical order in a dictionary), and Comparator as custom sorting (like sorting by page length, or date added).
🔸 Quick Comparison Table
| Feature | Comparable | Comparator |
|---|---|---|
| Package | java.lang |
java.util |
| Method | compareTo(Object o) |
compare(Object o1, Object o2) |
| Where Defined | Inside the class | Outside the class |
| Sorting Type | Natural (default) | Custom (multiple) |
| Multiple Sorts Possible? | No | Yes |
| Used With | Collections.sort(list) |
Collections.sort(list, comparator) |
| Example Use Case | Sort students by ID | Sort students by name, marks, etc. |
💻 Code Examples
✅ Example 1: Using Comparable (Natural Ordering)
import java.util.ArrayList;
import java.util.Collections;
import java.util.List;
class Student implements Comparable<Student> {
private int rollNo;
private String name;
public Student(int rollNo, String name) {
this.rollNo = rollNo;
this.name = name;
}
// Define natural ordering (by roll number)
@Override
public int compareTo(Student other) {
return Integer.compare(this.rollNo, other.rollNo);
}
@Override
public String toString() {
return rollNo + " - " + name;
}
}
public class ComparableExample {
public static void main(String[] args) {
List<Student> students = new ArrayList<>();
students.add(new Student(3, "Rahul"));
students.add(new Student(1, "Amit"));
students.add(new Student(2, "Sneha"));
Collections.sort(students); // uses compareTo()
System.out.println("Students sorted by roll number:");
students.forEach(System.out::println);
}
}
🧩 Explanation:
Here, Student implements Comparable<Student> and overrides compareTo() to sort by roll number.
Collections.sort() automatically applies this natural ordering.
✅ Example 2: Using Comparator (Custom Ordering)
import java.util.ArrayList;
import java.util.Collections;
import java.util.Comparator;
import java.util.List;
class Employee {
private String name;
private double salary;
public Employee(String name, double salary) {
this.name = name;
this.salary = salary;
}
public String getName() { return name; }
public double getSalary() { return salary; }
@Override
public String toString() {
return name + " - $" + salary;
}
}
public class ComparatorExample {
public static void main(String[] args) {
List<Employee> employees = new ArrayList<>();
employees.add(new Employee("Riya", 60000));
employees.add(new Employee("Arjun", 75000));
employees.add(new Employee("Meena", 55000));
// Comparator to sort by salary (descending)
Comparator<Employee> bySalaryDesc = (e1, e2) -> Double.compare(e2.getSalary(), e1.getSalary());
// Comparator to sort by name (alphabetically)
Comparator<Employee> byName = Comparator.comparing(Employee::getName);
// Sort using different comparators
Collections.sort(employees, bySalaryDesc);
System.out.println("Employees sorted by salary (descending):");
employees.forEach(System.out::println);
Collections.sort(employees, byName);
System.out.println("\nEmployees sorted by name:");
employees.forEach(System.out::println);
}
}
🧩 Explanation:
Here, we defined two different comparators:
- One sorts employees by salary (descending).
- Another sorts by name (alphabetically).
This flexibility is what makes Comparator powerful — you can plug in as many sorting rules as you need.
🧠 Best Practices
Use Comparable for natural sorting.
Define a single, logical ordering that represents the class’s identity — like sortingStudentbyrollNo.Use Comparator for flexibility.
When multiple sorting rules are needed, preferComparator. You can even chain them usingthenComparing().Avoid mixing both unnecessarily.
If a class already hasComparable, use external comparators only for alternate orders.Leverage Java 8+ features.
Use lambda expressions and method references for cleaner, more readable comparator code.Watch out for null values.
Handle nulls explicitly usingComparator.nullsFirst()orComparator.nullsLast()to avoidNullPointerException.
🏁 Conclusion
In Java programming, Comparable and Comparator both help define how objects are compared and sorted — but they serve different purposes:
- Comparable defines the default sorting logic inside the class.
- Comparator allows external, flexible sorting rules outside the class.
Mastering when and how to use them will make you more confident when working with complex sorting scenarios — from lists of names to detailed data models in enterprise applications.
Top comments (0)