Comparable<T> vs Comparator<T>
Natural ordering with Comparable; external ordering with Comparator — the contract and the builders.
Comparable — natural, built-in ordering
java.lang.Comparable<T> expresses that a class has a natural ordering defined within itself. Implement it and override compareTo:
public class Student implements Comparable<Student> {
String name;
int gpa;
Student(String name, int gpa) { this.name = name; this.gpa = gpa; }
@Override
public int compareTo(Student other) {
return Integer.compare(this.gpa, other.gpa); // ascending GPA
}
}
List<Student> list = new ArrayList<>(...);
Collections.sort(list); // uses compareTo — no extra argument needed
compareTo contract: return a negative integer when this < other, zero when equal, positive when this > other. The common mistake is writing this.x - other.x — this overflows for extreme int values. Use Integer.compare(a, b) instead.
Comparator — external, flexible ordering
java.util.Comparator<T> is a separate object that compares two values. It does not require the class to be modified:
// sort students by name, then by GPA descending
Comparator<Student> comp = Comparator
.comparing(Student::name)
.thenComparing(Comparator.comparingInt(Student::gpa).reversed());
list.sort(comp);
| | Comparable<T> | Comparator<T> |
|---|---|---|
| Lives in | The class itself | A separate object |
| Method | compareTo(T o) | compare(T a, T b) |
| Used by | Collections.sort, TreeSet | list.sort, TreeSet(comp) |
| Multiple orderings? | No — one natural order | Yes — compose as many as needed |