web-dev-qa-db-fra.com

Pourquoi ConcurrentHashMap empêche les clés et les valeurs nulles?

Le JavaDoc de ConcurrentHashMap dit ceci:

Comme Hashtable mais contrairement à HashMap, cette classe ne pas permet à null d'être utilisée comme clé ou valeur.

Ma question: pourquoi?

2ème question: pourquoi Hashtable n'autorise-t-il pas null?

J'ai utilisé beaucoup de HashMaps pour stocker des données. Mais lors du passage à ConcurrentHashMap, j'ai eu plusieurs fois des ennuis à cause de NullPointerExceptions.

132
Marcel

De l'auteur de ConcurrentHashMap lui-même (Doug Lea) :

La principale raison pour laquelle les valeurs NULL ne sont pas autorisées dans ConcurrentMaps (ConcurrentHashMaps, ConcurrentSkipListMaps) est que les ambiguïtés qui peuvent être à peine tolérables dans les cartes non simultanées ne peuvent pas être prises en compte. Le principal est que si map.get(key) renvoie null, vous ne pouvez pas détecter si la clé est explicitement mappée à null par rapport à la clé qui n'est pas mappée. Dans une mappe non simultanée, vous pouvez vérifier cela via map.contains(key), mais dans une mappe simultanée, la mappe peut avoir changé entre les appels.

208
Bruno

Je crois que c'est, au moins en partie, pour vous permettre de combiner containsKey et get en un seul appel. Si la carte peut contenir des valeurs NULL, il n'y a aucun moyen de savoir si get renvoie une valeur NULL car il n'y avait pas de clé pour cette valeur, ou simplement parce que la valeur était NULL.

Pourquoi c'est un problème? Parce qu'il n'y a aucun moyen sûr de le faire vous-même. Prenez le code suivant:

if (m.containsKey(k)) {
   return m.get(k);
} else {
   throw new KeyNotPresentException();
}

Étant donné que m est une mappe simultanée, la clé k peut être supprimée entre les appels containsKey et get, ce qui renvoie cet extrait de code qui n'a jamais été dans la table, plutôt que le KeyNotPresentException souhaité.

Normalement, vous pouvez résoudre ce problème en synchronisant, mais avec une carte simultanée, cela ne fonctionnera bien sûr pas. Par conséquent, la signature de get a dû changer, et la seule façon de le faire d'une manière rétrocompatible était d'empêcher l'utilisateur d'insérer des valeurs nulles en premier lieu et de continuer à l'utiliser comme espace réservé pour la clé " pas trouvé".

41
Alice Purcell

Josh Bloch a conçu HashMap; Doug Lea a conçu ConcurrentHashMap. J'espère que ce n'est pas diffamatoire. En fait, je pense que le problème est que les valeurs NULL nécessitent souvent un habillage pour que le vrai NULL puisse signifier non initialisé. Si le code client requiert des valeurs nulles, il peut payer le coût (certes faible) de l'encapsulation des valeurs nulles lui-même.

4

ConcurrentHashMap est thread-safe. Je crois que ne pas autoriser les clés et les valeurs nulles faisait partie de la vérification de la sécurité des threads.

0
Kevin Crowell

Vous ne pouvez pas synchroniser sur un null.

Edit: ce n'est pas exactement pourquoi dans ce cas. Au début, je pensais qu'il y avait quelque chose d'extraordinaire à verrouiller les choses contre les mises à jour simultanées ou à utiliser le moniteur d'objets pour détecter si quelque chose avait été modifié, mais en examinant le code source il semble que j'avais tort - ils se verrouillent en utilisant un "segment" basé sur un masque de bits du hachage.

Dans ce cas, je soupçonne qu'ils l'ont fait pour copier Hashtable, et je pense que Hashtable l'a fait parce que dans le monde de la base de données relationnelle, null! = Null, donc l'utilisation d'un null comme clé n'a pas de sens.

0
Paul Tomblin

Je suppose que l'extrait de code suivant de la documentation de l'API donne une bonne indication: "Cette classe est entièrement interopérable avec Hashtable dans les programmes qui reposent sur sa sécurité des threads mais pas sur ses détails de synchronisation."

Ils voulaient probablement juste rendre ConcurrentHashMap entièrement compatible/interchangeable avec Hashtable. Et comme Hashtable n'autorise pas les clés et les valeurs nulles.

0
Tobias Müller