Ответ
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().