Что происходит при добавлении в TreeMap элемента с ключом, который уже существует?

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

Ответ

TreeMap — реализация интерфейса SortedMap/NavigableMap, которая не допускает дубликатов ключей. При добавлении пары ключ-значение с ключом, который уже присутствует в мапе, происходит замена (перезапись) значения, связанного с этим ключом, на новое. Размер коллекции (size()) не изменяется.

Механизм работы метода put(K key, V value):

  1. На основе Comparator (если задан) или естественного порядка ключей (если ключ реализует Comparable) находится позиция ключа в красно-черном дереве.
  2. Если ключ уже существует, его текущее значение заменяется на новое, и метод возвращает старое значение.
  3. Если ключ отсутствует, создается новый узел в дереве, размер мапы увеличивается, и метод возвращает null.

Пример:

TreeMap<String, Integer> scores = new TreeMap<>();

// Первое добавление ключа "Alice"
scores.put("Alice", 100);
System.out.println(scores); // {Alice=100}
System.out.println(scores.size()); // 1

// Попытка добавить элемент с тем же ключом "Alice"
Integer oldValue = scores.put("Alice", 150); // Происходит ПЕРЕЗАПИСЬ

System.out.println("Old value: " + oldValue); // Old value: 100
System.out.println(scores); // {Alice=150} (значение обновлено)
System.out.println(scores.size()); // 1 (размер НЕ изменился)

Критически важные требования к ключам:

  • Сравнимость (Comparable/Comparator): Ключи должны быть сравнимы между собой. Если класс ключа не реализует Comparable и не передан Comparator в конструктор, при вызове put() будет выброшено ClassCastException.
  • Консистентность с equals(): Для корректной работы TreeMap порядок, заданный Comparator/Comparable, должен быть согласован с equals(). То есть compare(a, b) == 0 должен возвращать true тогда и только тогда, когда a.equals(b) == true. Стандартные реализации (например, String, Integer) соблюдают это правило.

Альтернатива для хранения нескольких значений на ключ: Если логика приложения требует ассоциировать с одним ключом несколько значений, используйте структуру Map<K, List<V>> или Map<K, Set<V>>.