Comparable is an interface implemented by the class of the object itself. It defines a single method compareTo(), which sets the natural order of sorting.
Comparator is a separate interface implementing the compare(o1, o2) method. It allows defining multiple ways of sorting without changing the class code itself.
When to use:
Examples:
// Comparable class Student implements Comparable<Student> { String name; int grade; public int compareTo(Student other) { return this.grade - other.grade; } } // Comparator Comparator<Student> byName = new Comparator<Student>() { public int compare(Student s1, Student s2) { return s1.name.compareTo(s2.name); } }; List<Student> students = ...; Collections.sort(students); // sorting by grade Collections.sort(students, byName); // sorting by name
Can you sort a List of objects that do not implement Comparable without a Comparator?
Answer: No. If the class does not implement Comparable and no Comparator is explicitly provided, attempting to sort the collection will result in a ClassCastException being thrown.
Example:
class Animal {} List<Animal> animals = ...; Collections.sort(animals); // ClassCastException if no Comparable
Story
In the inventory project, I forgot to implement Comparable for the Item class. There was an attempt to sort through Collections.sort(items). As a result, the application frequently crashed with ClassCastException due to the missing compareTo() method.
Story
In the student rating calculation service, the developer implemented comparison by the grade field only in the compareTo() method. Later, it was needed to sort by name and birth date, but the class code grew with auxiliary methods instead of using different Comparators and avoiding complex logic in compareTo().
Story
In the online order product, we tried to use a Comparator with a lambda expression to sort orders by date, but forgot to take into account the possibility of null date values. The result was unexpected NullPointerException in production when sorting orders without a delivery date.