🔗 Comparator vs Comparable
| Feature | Comparable | Comparator |
|---|---|---|
| Interface location | java.lang (core package) | java.util (utility package) |
| Purpose | Defines natural ordering of a class | Defines custom ordering for a class (outside the class itself) |
| Where to implement? | In the class itself (the class “knows” how to compare itself) | In a separate class (the comparison logic is external) |
| Method to implement | int compareTo(T o) | int compare(T o1, T o2) |
| Works with | Collections like TreeSet, TreeMap, Arrays.sort() (natural order) | Collections.sort() with custom logic |
| Flexibility | Only one ordering (natural order) | Can define multiple orderings for the same class |
| Example use case | Entities with a clear default order (like String, Integer) | Sorting objects differently based on user needs (e.g., sort by name, or by age) |
📜 Example — Using Comparable
Imagine a class Person where natural order is based on age:
class Person implements Comparable<Person> {
String name;
int age;
public Person(String name, int age) {
this.name = name;
this.age = age;
}
@Override
public int compareTo(Person other) {
return Integer.compare(this.age, other.age); // Natural order = by age
}
@Override
public String toString() {
return name + " (" + age + ")";
}
}
Sorting (Natural Order – Age):
List<Person> people = List.of(new Person("Alice", 30), new Person("Bob", 25));
List<Person> sorted = new ArrayList<>(people);
Collections.sort(sorted); // Works because Person implements Comparable
System.out.println(sorted); // [Bob (25), Alice (30)]
📜 Example — Using Comparator
Now you want to sort by name sometimes, and by age other times. A Comparator lets you do that:
class Person {
String name;
int age;
public Person(String name, int age) {
this.name = name;
this.age = age;
}
@Override
public String toString() {
return name + " (" + age + ")";
}
}
// Comparator to sort by name
Comparator<Person> byName = (p1, p2) -> p1.name.compareTo(p2.name);
// Comparator to sort by age (if not using Comparable)
Comparator<Person> byAge = Comparator.comparingInt(p -> p.age);
Usage:
List<Person> people = List.of(new Person("Alice", 30), new Person("Bob", 25));
List<Person> sortedByName = new ArrayList<>(people);
Collections.sort(sortedByName, byName); // Sort by name
System.out.println(sortedByName); // [Alice (30), Bob (25)]
List<Person> sortedByAge = new ArrayList<>(people);
Collections.sort(sortedByAge, byAge); // Sort by age
System.out.println(sortedByAge); // [Bob (25), Alice (30)]
🔥 Summary Table
| Feature | Comparable | Comparator |
|---|---|---|
| Defines ordering | Inside the class itself | Outside the class (external) |
| Flexibility | One order | Multiple orders (choose per sort) |
| Typical usage | Natural sorting (like alphabetic or numeric order) | Custom sorting (like by date, length, or multiple fields) |
| Sort method | Collections.sort(list) works directly | Collections.sort(list, comparator) needs comparator provided |
⚠️ When to Use What?
| Case | Use |
|---|---|
| Class has a clear natural order (like numbers, dates) | Comparable |
| You want to sort the same class in different ways (by name, age, etc.) | Comparator |
🎯 Quick Tip for Interviews
✅ Always mention Comparable is in the class itself, and Comparator is outside the class.
✅ Mention Comparable is like “self-sorting,” while Comparator allows “external sorting.”
✅ You can even combine both! A class can implement Comparable for default order, but you can still create Comparators for other orderings.