web-dev-qa-db-fra.com

Pourquoi Hashtable n'autorise-t-il pas les clés ou valeurs nulles?

Comme spécifié dans la documentation JDK, Hashtable n'autorise pas les clés ou valeurs nulles. HashMap autorise une clé NULL et un nombre quelconque de valeurs NULL. Pourquoi est-ce?

27
Love Hasija

Hashtable est la classe la plus ancienne et son utilisation est généralement déconseillée. Peut-être ont-ils perçu le besoin d'une clé nulle et, plus important encore, de valeurs nulles et l'ont ajouté à la mise en œuvre de HashMap.

HashMap est plus récent et dispose de fonctionnalités plus avancées, qui ne sont en fait qu'une amélioration de la fonctionnalité Hashtable. Lorsque HashMap a été créé, il était spécialement conçu pour gérer les valeurs NULL en tant que clés et les traiter comme un cas spécial.

Modifier

De HashtableJavaDoc :

Pour stocker et récupérer avec succès des objets d’une table de hachage, le fichier les objets utilisés comme clés doivent implémenter la méthode hashCode et la méthode equals.

Puisque null n'est pas un objet, vous ne pouvez pas appeler .equals() ou .hashCode(), le Hashtable ne peut donc pas calculer un hachage pour l'utiliser comme clé.

37
Jainendra

La principale raison pour laquelle Hashtable et ConcurrentHashMap n'autorisent pas les clés ou les valeurs null est due au fait qu'elles sont censées être utilisées dans un environnement multithread. Supposons pendant une minute que les valeurs NULL sont autorisées. Dans ce cas, la méthode get a un comportement ambigu. Il peut renvoyer null si la clé n'est pas trouvée dans la carte ou renvoyer null si la clé est trouvée et que sa valeur est null. Lorsqu'un code attend des valeurs NULL, il vérifie généralement si la clé est présente dans la carte afin de pouvoir savoir si la clé n'est pas présente ou si la clé est présente mais la valeur est null. Maintenant, ce code tombe dans un environnement multi-thread. Jetons un coup d'oeil au code ci-dessous:

if (map.contains(key)) {
    return map.get(key);
} else {
    throw new KeyNotFoundException;
}

Dans le code ci-dessus, supposons que le thread t1 appelle la méthode contient, trouve la clé et suppose que celle-ci est présente et prête à renvoyer la valeur, qu'elle soit nulle ou non. Maintenant, avant d'appeler map.get, un autre thread t2 supprime cette clé de la carte. Maintenant t1 reprend et renvoie null. Toutefois, conformément au code, la réponse correcte pour t1 est KeyNotFoundException car la clé a été supprimée. Mais il retourne toujours le null et le comportement attendu est donc cassé. 

Maintenant, pour un HashMap normal, il est supposé qu'il sera appelé par un seul thread, il n'y a donc aucune possibilité que la clé soit supprimée au milieu de "contient" check et "get". Donc HashMap peut tolérer des valeurs nulles. Cependant, pour Hashtable et ConcurrentHashMap, il est clair que plusieurs threads vont agir sur les données. Par conséquent, ils ne peuvent pas se permettre d’autoriser les valeurs NULL et de donner une réponse incorrecte. Même logique pour les clés. Maintenant, l'argument de compteur peut être - les étapes contient et obtenir pourraient échouer pour des valeurs non null pour Hashtables et ConcurrentHashMaps, car un autre thread peut modifier la carte/table avant que la deuxième étape ne soit exécutée. C'est correct, cela peut arriver. Mais comme Hashtables et ConcurrentHashMaps n'autorisent pas les clés et les valeurs NULL, il n'est pas nécessaire pour eux d'implémenter contient et obtient check en premier lieu. Ils peuvent directement obtenir la valeur car ils savent que si la méthode get renvoie null, la seule raison à cela est que la clé n'est pas présente et non pas parce que la valeur pourrait être null. La vérification contient et get est nécessaire uniquement pour HashMaps, car elles autorisent les valeurs null et doivent par conséquent résoudre l'ambiguïté quant à savoir si la clé est introuvable ou si la valeur est null. 

2
punitoza

La raison est la raison sur la réponse acceptée: Hashtable est vieux.

Cependant, l'utilisation de Hashtable IS ne s'est pas découragée en faveur de HashMap dans tous les cas de figure.

  • Hashtable est synchronisé, donc c'est THREAD-SAFE . HashMap n'est pas.

Ni Hashtable, ni ConcurrentHashMap ne prennent en charge les clés ou valeurs nulles. HashMap fait.

Si vous souhaitez un remplacement immédiat qui ne nécessite rien d'autre que de changer de classe et fonctionne dans tous les scénarios, il n'y en a pas. L'option la plus similaire serait ConcurrentHashMap (qui est thread-safe mais ne supporte pas le verrouillage de la table entière):

Cette classe est totalement interopérable avec Hashtable dans les programmes qui s'appuient sur sur son thread sécurité mais pas sur ses détails de synchronisation.

HashMap est un meilleur substitut pour les applications à un seul thread, ou la synchronisation n’est pas une nécessité, en raison de l’impact de la synchronisation sur les performances.

Sources:

2
NotGaeL

L'implémentation par défaut de la table de hachage permet de déterminer de manière précise quelle exception de pointeur null ... .. Les développeurs Java ont sans doute pris conscience de l'importance des clés nulles (pour certaines valeurs par défaut, etc.) et des valeurs, ainsi que la raison pour laquelle HashMap a été introduit.

Pour HashMap, la vérification de la valeur NULL existe pour les clés. Si la clé est NULL, cet élément sera stocké à un emplacement où le code de hachage n'est pas requis.

1
psl

La table de hachage est une classe très ancienne, à partir de JDK 1.0

Pour comprendre cela, nous devons d’abord comprendre les commentaires écrits sur cette classe par l’auteur . «Cette classe implémente une table de hachage, qui associe les clés aux valeurs. Tout objet non nul peut être utilisé comme clé ou comme valeur. Pour stocker et récupérer avec succès des objets d'une table de hachage, les objets utilisés en tant que clés doivent implémenter la méthode HashCode et la méthode equals. ”

La classe HashTable est implémentée sur un mécanisme de hachage, c’est-à-dire le moyen de stocker toute paire clé-valeur, son code de hachage requis pour l’objet clé. Si key est null, il ne pourra pas donner de hachage, il le fera via une exception de pointeur null et un cas similaire pour la valeur Il renvoie null si la valeur est null.

Mais plus tard, on s'est rendu compte que la clé et la valeur NULL avait sa propre importance, à savoir, pourquoi une clé NULL et plusieurs valeurs NULL sont autorisées dans les classes implémentées ultérieures telles que la classe HashMap.

Pour la carte de hachage, les clés NULL autoriseront et il y a une vérification nulle pour les clés Si la clé est nulle, cet élément sera stocké à un emplacement zéro dans le tableau Entry. clé nulle que nous pouvons utiliser pour certaines valeurs par défaut ..

=> Les méthodes Hashtable sont synchronisées, elles n'utilisent jamais de verrouillage basé sur les objets.

HashMap implémente en le considérant comme spécial

 static final int hash(Object key) {
        int h;
        return (key == null) ? 0 : (h = key.hashCode()) ^ (h >>> 16);
    }

Java 8, vous ne pouvez pas déduire les types pour la table de hachage.

private Map<String,String> hashtable = new Hashtable<>(); // Not Allowed

private Map<String,String> hashtable = new HashMap<>(); // Allowed
0
Kumar Abhishek

Comme @Jainendra l'a dit, HashTable n'autorise pas la clé nulle pour l'appel key.hashCode () dans put().

Mais il semble que personne ne réponde clairement pourquoi la valeur null n'est pas autorisée.

public synchronized V put(K key, V value) {
    // Make sure the value is not null
    if (value == null) {
        throw new NullPointerException();
    }

    // Makes sure the key is not already in the hashtable.
    Entry<?,?> tab[] = table;
    int hash = key.hashCode();
    int index = (hash & 0x7FFFFFFF) % tab.length;
    @SuppressWarnings("unchecked")
    Entry<K,V> entry = (Entry<K,V>)tab[index];
    for(; entry != null ; entry = entry.next) {
        if ((entry.hash == hash) && entry.key.equals(key)) {
            V old = entry.value;
            entry.value = value;
            return old;
        }
    }

    addEntry(hash, key, value, index);
    return null;
}

L'enregistrement null dans put n'explique pas pourquoi la valeur null est illégale, elle garantit simplement un invariant non null.

La réponse concrète à la valeur null null est HashTable appellera value.equals lors de l'appel contains/remove.

0
Jiacai Liu

donc pour conclure

Parce que dans HashTable, lorsque vous mettez un élément, il prend en compte le hachage de la clé et de la valeur. En gros, vous aurez quelque chose comme:

public Object put(Object key, Object value){

    key.hashCode();

    //some code

    value.hashCode();

}

HashTable - N'autorise pas les clés null C'est parce que, dans la méthode put (clé K, valeur V), nous avons key.hashcode () qui lève une exception de pointeur null . HashTable - N'autorise pas la valeur null .__ C’est parce que, en méthode put (clé K, valeur V), nous avons la méthode if (valeur == null) {en ouvrant une nouvelle exception NullPointerException

HashMap autorise les valeurs NULL car il ne comporte aucune vérification comme HashTable, alors qu'il n'autorise qu'une seule clé NULL. Cette opération est effectuée à l'aide de la méthode putForNullKey, qui ajoute la valeur à l'index 0 du tableau interne chaque fois que la clé est fournie avec la valeur null.

0
Rehan