Для чего в TreeMap (Java) может понадобиться Comparator?

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

Ответ

Comparator в TreeMap нужен для того, чтобы задать пользовательский порядок сортировки ключей, отличный от их естественного порядка (заданного Comparable).

Контекст: По умолчанию TreeMap<K, V> сортирует ключи по их естественному порядку, что требует, чтобы класс ключа K реализовывал интерфейс Comparable<K>. Если ключи не реализуют Comparable или вам нужна иная логика сортировки, вы должны передать Comparator в конструктор TreeMap.

Практические причины использования Comparator с TreeMap:

  1. Ключи не реализуют Comparable. Например, использование массива int[] в качестве ключа (массивы не реализуют Comparable).
  2. Требуется сортировка, отличная от естественной. Например, сортировка строк (String) без учета регистра или в обратном алфавитном порядке.
  3. Необходимо избежать ClassCastException. При добавлении в TreeMap ключей, не поддерживающих сравнение, будет выброшено исключение. Comparator решает эту проблему.

Примеры:

// 1. TreeMap с ключами String, отсортированными без учета регистра
Map<String, Integer> caseInsensitiveMap = new TreeMap<>(String.CASE_INSENSITIVE_ORDER);

// 2. TreeMap с ключами String, отсортированными в обратном порядке
Map<String, Integer> reverseMap = new TreeMap<>(Comparator.reverseOrder());

// 3. TreeMap с пользовательским Comparator для сложных ключей
Comparator<Person> byAgeThenName = Comparator
        .comparingInt(Person::getAge)
        .thenComparing(Person::getName);
Map<Person, String> customOrderMap = new TreeMap<>(byAgeThenName);

Без переданного Comparator TreeMap будет пытаться использовать compareTo() у ключей, что может привести к ошибке или нежелательному порядку.