Comparable vs Comparator in Java: Key Differences and Usage
Comparable is an interface used to define the natural ordering of objects by implementing the compareTo() method within the class itself. Comparator is a separate interface used to define custom orderings by implementing the compare() method externally, allowing multiple sorting strategies.Quick Comparison
This table summarizes the main differences between Comparable and Comparator interfaces in Java.
| Aspect | Comparable | Comparator |
|---|---|---|
| Purpose | Defines natural ordering inside the class | Defines custom ordering outside the class |
| Method to implement | compareTo(T o) | compare(T o1, T o2) |
| Location | Implemented by the class of objects to be sorted | Implemented by a separate class or lambda expression |
| Number of sort sequences | Only one natural order | Multiple different orders possible |
| Modification | Requires modifying the class | No need to modify the class |
| Java 8+ support | Can use default methods | Supports lambda expressions and method references |
Key Differences
Comparable is used when a class has a single natural ordering. The class implements the Comparable interface and overrides the compareTo() method to define how objects of that class should be compared. This means the sorting logic is inside the class itself.
On the other hand, Comparator is a separate interface that allows defining multiple ways to compare objects without changing the class. You implement the compare() method in a different class or use lambda expressions to create custom sorting rules. This is useful when you want to sort objects in different ways at different times.
In summary, use Comparable for a default, single sorting order embedded in the class, and use Comparator when you need flexibility to sort objects differently without modifying their class.
Code Comparison
Here is an example using Comparable to sort a list of Person objects by their age (natural order):
import java.util.*; class Person implements Comparable<Person> { String name; int age; Person(String name, int age) { this.name = name; this.age = age; } @Override public int compareTo(Person other) { return Integer.compare(this.age, other.age); } @Override public String toString() { return name + "(" + age + ")"; } } public class ComparableExample { public static void main(String[] args) { List<Person> people = new ArrayList<>(); people.add(new Person("Alice", 30)); people.add(new Person("Bob", 25)); people.add(new Person("Charlie", 35)); Collections.sort(people); System.out.println(people); } }
Comparator Equivalent
Here is the same sorting task done using a Comparator to sort Person objects by age without modifying the Person class:
import java.util.*; class Person { String name; int age; Person(String name, int age) { this.name = name; this.age = age; } @Override public String toString() { return name + "(" + age + ")"; } } public class ComparatorExample { public static void main(String[] args) { List<Person> people = new ArrayList<>(); people.add(new Person("Alice", 30)); people.add(new Person("Bob", 25)); people.add(new Person("Charlie", 35)); Comparator<Person> ageComparator = (p1, p2) -> Integer.compare(p1.age, p2.age); Collections.sort(people, ageComparator); System.out.println(people); } }
When to Use Which
Choose Comparable when your class has a clear natural order that makes sense for most uses, and you want to embed this order inside the class itself. This is simpler and makes sorting straightforward.
Choose Comparator when you need multiple ways to sort objects, or when you cannot modify the class (for example, classes from external libraries). Comparator offers flexibility and keeps sorting logic separate.
In practice, use Comparable for default sorting and Comparator for custom or multiple sorting strategies.