JavaDoc ConcurrentHashMap
mówi tak:
Podobnie jak,
Hashtable
ale w przeciwieństwie doHashMap
tej klasy, ta klasa nie pozwalanull
na użycie jako klucza lub wartości.
Moje pytanie: dlaczego?
Drugie pytanie: Dlaczego nie Hashtable
zezwala na null?
Używałem wielu HashMap do przechowywania danych. Ale przy zmianie na ConcurrentHashMap
kilka razy miałem kłopoty z powodu wyjątków NullPointerExceptions.
java
concurrenthashmap
Marcel
źródło
źródło
Odpowiedzi:
Od samego autora
ConcurrentHashMap
(Doug Lea) :źródło
Optional
s jako wartości wewnętrznieOptional
to funkcja Java 8, która nie była wtedy dostępna (Java 5).Optional
Rzeczywiście, możesz teraz użyć s.Uważam, że przynajmniej częściowo umożliwia to połączenie
containsKey
iget
utworzenie jednej rozmowy. Jeśli mapa może przechowywać wartości null, nie ma sposobu, aby stwierdzić, czyget
zwraca wartość null, ponieważ nie było klucza dla tej wartości, czy tylko dlatego, że wartość była pusta.Dlaczego to jest problemem? Ponieważ nie ma na to bezpiecznego sposobu. Weź następujący kod:
Ponieważ
m
jest to mapa współbieżna, klucz k może zostać usunięty między wywołaniamicontainsKey
iget
, powodując, że ten fragment kodu zwraca wartość null, której nigdy nie było w tabeli, zamiast pożądanegoKeyNotPresentException
.Zwykle można to rozwiązać przez synchronizację, ale z mapą współbieżną to oczywiście nie zadziała. W związku z tym podpis for
get
musiał się zmienić, a jedynym sposobem, aby to zrobić w sposób zgodny z poprzednimi wersjami, było uniemożliwienie użytkownikowi wstawiania wartości null w pierwszej kolejności i dalsze używanie tego jako symbolu zastępczego dla „klucza nie znaleziono”.źródło
map.getOrDefault(key, NULL_MARKER)
. Jeśli taknull
, wartość wynosiłanull
. Jeśli zwróciNULL_MARKER
, wartość nie była obecna.Josh Bloch zaprojektował
HashMap
; Zaprojektował Doug LeaConcurrentHashMap
. Mam nadzieję, że to nie jest zniesławiające. Właściwie myślę, że problem polega na tym, że wartości null często wymagają zawijania, aby prawdziwy null mógł oznaczać niezainicjowany. Jeśli kod klienta wymaga wartości null, może zapłacić (co prawda niewielki) koszt pakowania wartości null.źródło
Nie możesz synchronizować wartości null.
Edycja: w tym przypadku nie jest to dokładnie powód. Początkowo myślałem, że dzieje się coś wymyślnego z blokowaniem rzeczy przed równoczesnymi aktualizacjami lub w inny sposób korzystaniem z monitora obiektów do wykrywania, czy coś zostało zmodyfikowane, ale po zbadaniu kodu źródłowego wydaje się, że się myliłem - blokują używając „segmentu” opartego na maska bitowa skrótu.
W takim przypadku podejrzewam, że zrobili to, aby skopiować Hashtable, i podejrzewam, że Hashtable to zrobił, ponieważ w świecie relacyjnych baz danych null! = Null, więc użycie null jako klucza nie ma żadnego znaczenia.
źródło
ConcurrentHashMap jest bezpieczna wątkowo. Uważam, że niedopuszczenie pustych kluczy i wartości było częścią upewnienia się, że jest bezpieczny dla wątków.
źródło
Wydaje mi się, że poniższy fragment dokumentacji API daje dobrą wskazówkę: „Ta klasa jest w pełni interoperacyjna z Hashtable w programach, które polegają na bezpieczeństwie wątków, ale nie na szczegółach synchronizacji”.
Prawdopodobnie chcieli tylko, aby w
ConcurrentHashMap
pełni kompatybilny / wymienny zHashtable
. A ponieważHashtable
nie zezwala na puste klucze i wartości.źródło
Nie sądzę, aby odrzucenie wartości null było właściwą opcją. W wielu przypadkach chcemy umieścić klucz z wartością null w mapie współbieżnej. Jednak używając ConcurrentHashMap, nie możemy tego zrobić. Sugeruję, że nadchodząca wersja JDK może to wspierać.
źródło