«Возможно, проблема не в том, что нас ничего не беспокоит, а в том, что мы это беспокоим».
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()нулевой объект), но нулевые значения не являются чем-то особенным, они хранятся на карте, как и все остальное
Итак, если .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ключа будут корневые узлы.
Одним из примеров использования nullзначений является использование a HashMapв качестве кеша для результатов дорогостоящей операции (например, вызова внешней веб-службы), которая может возвращаться null.
nullЗатем размещение значения на карте позволяет вам различать случай, когда операция не была выполнена для данного ключа ( cache.containsKey(someKey)возврат false), и случай , когда операция была выполнена, но вернула nullзначение ( cache.containsKey(someKey)возврат true, cache.get(someKey)возврат null).
Без nullзначений вам придется либо поместить какое-то специальное значение в кеш, чтобы указать nullответ, либо просто не кешировать этот ответ вообще и выполнять операцию каждый раз.
Пока ответы учитывают только ценность nullключа, но вопрос также задает вопрос any number of null values.
Преимущество сохранения значения nullпо ключу в HashMap такое же, как и в базах данных и т. Д. - вы можете записать различие между наличием значения, которое является пустым (например, строка ""), и отсутствием значения вообще (null) .
Вот мой единственный, несколько надуманный пример случая, когда nullключ может быть полезен:
publicclassTimer{
privatestaticfinal Logger LOG = Logger.getLogger(Timer.class);
privatestaticfinal Map<String, Long> START_TIMES = new HashMap<String, Long>();
publicstaticsynchronizedvoidstart(){
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);
}
publicstaticsynchronizedlongstop(){
if (! START_TIMES.containsKey(null)) {
return0;
}
return printTimer("Anonymous", START_TIMES.remove(null), System.currentTimeMillis());
}
publicstaticsynchronizedvoidstart(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);
}
publicstaticsynchronizedlongstop(String name){
if (! START_TIMES.containsKey(name)) {
return0;
}
return printTimer(name, START_TIMES.remove(name), System.currentTimeMillis());
}
privatestaticlongprintTimer(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"
Нулевой ключ также может быть полезен, когда на карте хранятся данные для выбора пользовательского интерфейса, где ключ карты представляет собой поле компонента.
Соответствующее значение пустого поля, например, будет представлено как «(пожалуйста, выберите)» в выборе пользовательского интерфейса.
ConcurrentHashMap
он не поддерживает нулевые ключи, аHashMap
поддерживает.Ответы:
Я не уверен в том, что вы спрашиваете, но если вы ищете пример того, когда можно было бы использовать нулевой ключ, я часто использую их в картах для представления случая по умолчанию (т.е. значения, которое следует использовать если данный ключ отсутствует):
Map<A, B> foo; A search; B val = foo.containsKey(search) ? foo.get(search) : foo.get(null);
HashMap
обрабатывает нулевые ключи специально (поскольку он не может вызывать.hashCode()
нулевой объект), но нулевые значения не являются чем-то особенным, они хранятся на карте, как и все остальноеисточник
HashMap
(putForNullKey
) , который обрабатывает его; он хранит его в таблице 0B val = foo.containsKey(search) ? foo.get(search) : foo.get(null);
я думаю, мы можем просто вызвать метод get для ключа поиска, который будет иметь такой же результат.B val = foo.get(search);
не могли бы вы поправить меня, если я ошибаюсь?val
на,null
если ключ не существует; мой устанавливает его для любыхnull
карт на карте. В том-то и дело, я сохраняю ненулевое значение по умолчанию вnull
ключе на карте и использую его, если фактический ключ не существует,Одним из примеров может служить моделирование деревьев. Если вы используете HashMap для представления древовидной структуры, где ключ является родительским, а значение - списком дочерних элементов, то значениями для
null
ключа будут корневые узлы.источник
Одним из примеров использования
null
значений является использование aHashMap
в качестве кеша для результатов дорогостоящей операции (например, вызова внешней веб-службы), которая может возвращатьсяnull
.null
Затем размещение значения на карте позволяет вам различать случай, когда операция не была выполнена для данного ключа (cache.containsKey(someKey)
возвратfalse
), и случай , когда операция была выполнена, но вернулаnull
значение (cache.containsKey(someKey)
возвратtrue
,cache.get(someKey)
возвратnull
).Без
null
значений вам придется либо поместить какое-то специальное значение в кеш, чтобы указатьnull
ответ, либо просто не кешировать этот ответ вообще и выполнять операцию каждый раз.источник
Пока ответы учитывают только ценность
null
ключа, но вопрос также задает вопросany number of null values
.Преимущество сохранения значения
null
по ключу в HashMap такое же, как и в базах данных и т. Д. - вы можете записать различие между наличием значения, которое является пустым (например, строка ""), и отсутствием значения вообще (null) .источник
Вот мой единственный, несколько надуманный пример случая, когда
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; } }
источник
throw Exception
. Кроме того, это не похоже на попытку остановить несуществующий или уже остановленный таймер - это то, от чего вызывающий обычно может восстановиться.Другой пример: я использую его для группировки данных по дате. Но у некоторых данных нет даты. Я могу сгруппировать его с заголовком "NoDate"
источник
Нулевой ключ также может быть полезен, когда на карте хранятся данные для выбора пользовательского интерфейса, где ключ карты представляет собой поле компонента.
Соответствующее значение пустого поля, например, будет представлено как «(пожалуйста, выберите)» в выборе пользовательского интерфейса.
источник