null в TreeMap

TreeMap хранит ключи в отсортированном виде. Поэтому для каждой пары ключей он должен уметь определить порядок: через естественное сравнение Comparable или переданный Comparator.

null как ключ

При естественном порядке null использовать нельзя:

Map<String, Integer> scores = new TreeMap<>();
scores.put(null, 10); // NullPointerException

У null нет метода compareTo, поэтому сравнить его с другим ключом невозможно.

Если порядок задаёт компаратор и он явно умеет обрабатывать null, такой ключ допустим:

Comparator<String> comparator =
        Comparator.nullsFirst(Comparator.naturalOrder());
 
Map<String, Integer> scores = new TreeMap<>(comparator);
scores.put("beta", 2);
scores.put(null, 0);
scores.put("alpha", 1);
 
System.out.println(scores);
// {null=0, alpha=1, beta=2}

Это часть контракта конкретного компаратора, а не общее свойство всех TreeMap.

null как значение

Значения не участвуют в сортировке, поэтому TreeMap разрешает null-значения:

Map<String, Integer> scores = new TreeMap<>();
scores.put("alpha", null);

Как и у других реализаций Map, результат get(key) == null неоднозначен: ключа может не быть либо с ним может быть связано значение null. Для проверки нужен containsKey(key).

Что важно запомнить

  • при естественном порядке null-ключ приводит к NullPointerException;
  • null-ключ возможен только с подходящим компаратором;
  • null-значения разрешены;
  • компаратор должен задавать согласованный порядок, иначе операции поиска и обновления будут вести себя неожиданно.

На собеседовании

Почему HashMap обычно принимает один null-ключ, а TreeMap — нет?

HashMap выбирает корзину по хешу и имеет отдельную обработку null. TreeMap должен сравнивать ключи, а естественное сравнение для null не определено. Пользовательский компаратор может определить такой порядок явно.

Связанные заметки