Comparable — это интерфейс, который реализуется самим классом объекта. Определяет один метод compareTo(), определяющий естественный порядок сортировки.
Comparator — отдельный интерфейс, реализующий метод compare(o1, o2). Позволяет определять несколько способов сортировки без изменения кода самого класса.
Когда использовать:
Примеры:
// 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); // сортировка по grade Collections.sort(students, byName); // сортировка по name
Можно ли сортировать List объектов, не реализующих Comparable, без Comparator?
Ответ: Нет. Если класс не реализует Comparable и явно не передан Comparator, попытка сортировки коллекции приведёт к выбросу ClassCastException.
Пример:
class Animal {} List<Animal> animals = ...; Collections.sort(animals); // ClassCastException, если нет Comparable
История
В проекте инвентаризации забыл реализовать Comparable для класса Item. Была попытка сортировки через Collections.sort(items). В результате приложение регулярно падало с ClassCastException из-за отсутствия метода compareTo().
История
В сервисе расчета рейтингов учеников разработчик реализовал сравнение по полю grade только в методе compareTo(). Позже понадобилось сортировать по имени и по дате рождения, но код класса разросся вспомогательными методами, вместо того чтобы использовать разные Comparator и избежать сложной логики в compareTo().
История
В продукте для онлайн-заказов попытались использовать Comparator с лямбда-выражением для сортировки заказов по дате, однако забыли учесть возможность null-значений даты. Итог — неожиданные NullPointerException в продакшене при сортировке заказов без даты доставки.