Какие требования к ключам в TreeMap в Java?

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

Ответ

TreeMap требует, чтобы ключи были сравнимыми. Есть два способа обеспечить это:

1. Ключи реализуют Comparable<T>

class Person implements Comparable<Person> {
    private String name;

    @Override
    public int compareTo(Person other) {
        return this.name.compareTo(other.name);
    }
}

// Использование
TreeMap<Person, String> map = new TreeMap<>();
map.put(new Person("Alice"), "Developer");

2. Передача Comparator<K> в конструктор

// Сортировка по убыванию
Comparator<String> reverseOrder = (a, b) -> b.compareTo(a);
TreeMap<String, Integer> map = new TreeMap<>(reverseOrder);

// Сложная логика сравнения
Comparator<Employee> bySalaryThenName = Comparator
    .comparingInt(Employee::getSalary)
    .thenComparing(Employee::getName);
TreeMap<Employee, String> employees = new TreeMap<>(bySalaryThenName);

3. Ограничения и особенности

Null-ключи

// По умолчанию НЕ поддерживаются
TreeMap<String, String> map1 = new TreeMap<>();
// map1.put(null, "value"); // NullPointerException

// Можно разрешить через Comparator
Comparator<String> nullsFirst = Comparator.nullsFirst(String::compareTo);
TreeMap<String, String> map2 = new TreeMap<>(nullsFirst);
map2.put(null, "valid"); // Работает

Консистентность сравнения

// НЕКОРРЕКТНО: compareTo не согласован с equals
class InconsistentKey implements Comparable<InconsistentKey> {
    int id;
    String name;

    public int compareTo(InconsistentKey o) {
        return Integer.compare(id, o.id); // Сравниваем только id
    }

    public boolean equals(Object o) {
        // Но equals сравнивает и id, и name!
        // Это нарушает контракт SortedMap
    }
}

4. Производительность

  • Вставка, удаление, поиск: O(log n)
  • Основан на красно-чёрном дереве
  • Гарантирует порядок итерации согласно компаратору

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