Какая польза от добавления нулевого ключа или значения в HashMap в Java?

91

HashMap допускает один нулевой ключ и любое количество нулевых значений. Какая от этого польза?

субхаши
источник
11
«Возможно, проблема не в том, что нас ничего не беспокоит, а в том, что мы это беспокоим».
bmargulies
3
В Guava, коллекциях Google многие классы не допускают null, и причина этого в том, что 95% случаев не нуждаются в null и могут представлять ошибки, которые потенциально трудно найти.
Стивло
Странно то, что ConcurrentHashMapон не поддерживает нулевые ключи, а HashMapподдерживает.
codepleb
2
Только HashMap допускает null :)
subhashis

Ответы:

126

Я не уверен в том, что вы спрашиваете, но если вы ищете пример того, когда можно было бы использовать нулевой ключ, я часто использую их в картах для представления случая по умолчанию (т.е. значения, которое следует использовать если данный ключ отсутствует):

Map<A, B> foo;
A search;
B val = foo.containsKey(search) ? foo.get(search) : foo.get(null);

HashMapобрабатывает нулевые ключи специально (поскольку он не может вызывать .hashCode()нулевой объект), но нулевые значения не являются чем-то особенным, они хранятся на карте, как и все остальное

Майкл Мрозек
источник
4
Итак, если .hashCode () невозможен для null, кто решает, в какую каретку войдет нулевой ключ?
Pacerier
26
@Pacerier Там особый метод HashMap( putForNullKey) , который обрабатывает его; он хранит его в таблице 0
Майкл Мрозек,
1
@MichaelMrozek, ваша последняя строка, B val = foo.containsKey(search) ? foo.get(search) : foo.get(null);я думаю, мы можем просто вызвать метод get для ключа поиска, который будет иметь такой же результат. B val = foo.get(search);не могли бы вы поправить меня, если я ошибаюсь?
dheerajraaj
6
@ dheeraj92 Ваш код будет установлен valна, nullесли ключ не существует; мой устанавливает его для любых nullкарт на карте. В том-то и дело, я сохраняю ненулевое значение по умолчанию в nullключе на карте и использую его, если фактический ключ не существует,
Майкл
28

Одним из примеров может служить моделирование деревьев. Если вы используете HashMap для представления древовидной структуры, где ключ является родительским, а значение - списком дочерних элементов, то значениями для nullключа будут корневые узлы.

Тони
источник
6

Одним из примеров использования null значений является использование a HashMapв качестве кеша для результатов дорогостоящей операции (например, вызова внешней веб-службы), которая может возвращаться null.

nullЗатем размещение значения на карте позволяет вам различать случай, когда операция не была выполнена для данного ключа ( cache.containsKey(someKey)возврат false), и случай , когда операция была выполнена, но вернула nullзначение ( cache.containsKey(someKey)возврат true, cache.get(someKey)возврат null).

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

Zorac
источник
3

Пока ответы учитывают только ценность nullключа, но вопрос также задает вопрос any number of null values.

Преимущество сохранения значения nullпо ключу в HashMap такое же, как и в базах данных и т. Д. - вы можете записать различие между наличием значения, которое является пустым (например, строка ""), и отсутствием значения вообще (null) .

Эборбоб
источник
2

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

public class Timer {
    private static final Logger LOG = Logger.getLogger(Timer.class);
    private static final Map<String, Long> START_TIMES = new HashMap<String, Long>();

    public static synchronized void start() {
        long now = System.currentTimeMillis();
        if (START_TIMES.containsKey(null)) {
            LOG.warn("Anonymous timer was started twice without being stopped; previous timer has run for " + (now - START_TIMES.get(null).longValue()) +"ms"); 
        }
        START_TIMES.put(null, now);
    }

    public static synchronized long stop() {
        if (! START_TIMES.containsKey(null)) {
            return 0;
        }

        return printTimer("Anonymous", START_TIMES.remove(null), System.currentTimeMillis());
    }

    public static synchronized void start(String name) {
        long now = System.currentTimeMillis();
        if (START_TIMES.containsKey(name)) {
            LOG.warn(name + " timer was started twice without being stopped; previous timer has run for " + (now - START_TIMES.get(name).longValue()) +"ms"); 
        }
        START_TIMES.put(name, now);
    }

    public static synchronized long stop(String name) {
        if (! START_TIMES.containsKey(name)) {
            return 0;
        }

        return printTimer(name, START_TIMES.remove(name), System.currentTimeMillis());
    }

    private static long printTimer(String name, long start, long end) {
        LOG.info(name + " timer ran for " + (end - start) + "ms");
        return end - start;
    }
}
арот
источник
Если вы пытаетесь остановить несуществующий таймер или тот, который уже был остановлен, это должно быть ошибкой, а не игнорироваться.
Иск Фонда Моники
@QPaysTaxes - Зависит от ваших намерений. Если вам нужна легкая утилита, которую можно легко использовать, вам обычно не нужно ее использовать throw Exception. Кроме того, это не похоже на попытку остановить несуществующий или уже остановленный таймер - это то, от чего вызывающий обычно может восстановиться.
aroth 03
1

Другой пример: я использую его для группировки данных по дате. Но у некоторых данных нет даты. Я могу сгруппировать его с заголовком "NoDate"

Anthone
источник
0

Нулевой ключ также может быть полезен, когда на карте хранятся данные для выбора пользовательского интерфейса, где ключ карты представляет собой поле компонента.

Соответствующее значение пустого поля, например, будет представлено как «(пожалуйста, выберите)» в выборе пользовательского интерфейса.

Гуннар
источник