Чем интерфейс Comparator отличается от Comparable в Java?

«Чем интерфейс Comparator отличается от Comparable в Java?» — вопрос из категории Java Core, который задают на 10% собеседований Java Разработчик. Ниже — развёрнутый ответ с разбором ключевых моментов.

Ответ

Comparator<T> — это функциональный интерфейс для определения внешнего (альтернативного) порядка сортировки, независимого от класса объектов. Он предоставляет метод compare(T o1, T o2) для сравнения двух аргументов.

Ключевое отличие: Критерий Comparable<T> Comparator<T>
Пакет java.lang java.util
Метод int compareTo(T o) int compare(T o1, T o2)
Смысл Определяет естественный порядок (внутренний для класса) Определяет произвольный порядок (внешний, отдельный класс/лямбда)
Влияние на класс Модифицирует исходный класс (реализация интерфейса) Не требует изменения исходного класса
Количество вариантов Один (естественный) Множество (по разным полям и правилам)

Примеры использования Comparator:

  1. Сортировка строк по длине (лямбда):

    List<String> words = Arrays.asList("apple", "fig", "banana");
    Comparator<String> byLength = (s1, s2) -> s1.length() - s2.length();
    words.sort(byLength); // [fig, apple, banana]
  2. Цепочка компараторов (сортировка по нескольким полям):

    List<Person> people = ...;
    people.sort(
        Comparator.comparing(Person::getLastName)  // Сначала по фамилии
                  .thenComparing(Person::getAge)   // Затем по возрасту
                  .reversed()                      // В обратном порядке
    );
  3. Сортировка по null-безопасному полю:

    Comparator<Person> safeComparator = 
        Comparator.nullsLast(Comparator.comparing(Person::getName));

Области применения:

  • Сортировка коллекций, когда класс не реализует Comparable.
  • Задание порядка, отличного от естественного.
  • Использование в SortedSet (например, TreeSet) и SortedMap (TreeMap) с кастомным порядком.
  • Передача логики сравнения как параметра (стратегия).