В JavaDoc ConcurrentHashMap
говорится следующее:
Как ,
Hashtable
но в отличие отHashMap
, этот класс никак не позволяетnull
использовать в качестве ключа или значения.
Мой вопрос: почему?
2-й вопрос: почему не Hashtable
разрешено null?
Я использовал много HashMaps для хранения данных. Но при переходе на ConcurrentHashMap
несколько раз у меня возникали проблемы из-за NullPointerExceptions.
java
concurrenthashmap
Марсель
источник
источник
Ответы:
От самого автора
ConcurrentHashMap
(Дуга Ли) :источник
Optional
s в качестве значений для внутреннего использованияOptional
- это функция Java 8, которая тогда была недоступна (Java 5). ВыOptional
действительно можете использовать s сейчас.Я считаю , что это, по крайней мере частично, позволяют объединять
containsKey
иget
в один вызов. Если карта может содержать значения NULL, невозможно определить,get
возвращает ли значение NULL, потому что не было ключа для этого значения или просто потому, что значение было нулевым.Почему это проблема? Потому что нет безопасного способа сделать это самостоятельно. Возьмите следующий код:
if (m.containsKey(k)) { return m.get(k); } else { throw new KeyNotPresentException(); }
Поскольку
m
это одновременное отображение, ключ к может быть удален междуcontainsKey
иget
вызовов, в результате чего этот фрагмент кода , чтобы возвратить нуль , что никогда не был в таблице, а не желаемоеKeyNotPresentException
.Обычно вы решаете это путем синхронизации, но с параллельной картой это, конечно, не сработает. Следовательно, подпись для
get
должна была быть изменена, и единственный способ сделать это обратно совместимым способом - не допустить, чтобы пользователь вставлял нулевые значения в первую очередь, и продолжать использовать это как заполнитель для «ключ не найден».источник
map.getOrDefault(key, NULL_MARKER)
. Если даnull
, то значение былоnull
. Если он возвращаетсяNULL_MARKER
, значение не было.Дизайн Джоша Блоха
HashMap
; Дизайн Дуга ЛиConcurrentHashMap
. Надеюсь, это не клевета. На самом деле я думаю, что проблема в том, что нули часто требуют переноса, чтобы реальный ноль мог обозначать неинициализированный. Если клиентскому коду требуются значения NULL, он может оплатить (по общему признанию небольшую) стоимость самой упаковки NULL.источник
Вы не можете синхронизировать по нулю.
Изменить: это не совсем то, почему в этом случае. Сначала я подумал, что происходит что-то необычное с блокировкой чего-либо против одновременных обновлений или иным образом с использованием монитора объектов для определения того, было ли что-то изменено, но после изучения исходного кода оказалось, что я ошибался - они блокируют использование «сегмента» на основе битовая маска хеша.
В этом случае я подозреваю, что они сделали это для копирования Hashtable, и я подозреваю, что Hashtable сделал это, потому что в мире реляционных баз данных null! = Null, поэтому использование null в качестве ключа не имеет смысла.
источник
ConcurrentHashMap является потокобезопасным. Я считаю, что запрет на использование пустых ключей и значений был частью обеспечения потоковой безопасности.
источник
Я предполагаю, что следующий фрагмент документации API дает хороший намек: «Этот класс полностью совместим с Hashtable в программах, которые полагаются на его безопасность потоков, но не на его детали синхронизации».
Вероятно, они просто хотели сделать
ConcurrentHashMap
полностью совместимыми / взаимозаменяемымиHashtable
. А такHashtable
же не допускает нулевых ключей и значений ..источник
Я не думаю, что запрет на нулевое значение - правильный вариант. Во многих случаях мы действительно хотим поместить ключ с нулевым значением в текущую карту. Однако, используя ConcurrentHashMap, мы не можем этого сделать. Я предполагаю, что будущая версия JDK может это поддерживать.
источник