web-dev-qa-db-de.com

Warum erlaubt Hashtable keine Nullschlüssel oder Werte?

Wie in der JDK-Dokumentation angegeben, erlaubt Hashtable keine Nullschlüssel oder -werte. HashMap erlaubt einen Nullschlüssel und eine beliebige Anzahl von Nullwerten. Warum ist das?

27
Love Hasija

Hashtable ist die ältere Klasse und wird im Allgemeinen davon abgeraten. Vielleicht sahen sie die Notwendigkeit eines Nullschlüssels und vor allem von Nullwerten und fügten ihn der HashMap-Implementierung hinzu.

HashMap ist neuer und bietet erweiterte Funktionen, die im Grunde nur eine Verbesserung der Hashtable-Funktionalität darstellen. Wenn HashMap erstellt wurde, wurde es speziell dafür entwickelt, Nullwerte als Schlüssel und als Sonderfall zu behandeln.

Bearbeiten

Von HashtableJavaDoc :

Zum erfolgreichen Speichern und Abrufen von Objekten aus einer Hashtabelle wird der Als Schlüssel verwendete Objekte müssen die Methode hashCode und die Methode equals implementieren.

Da null kein Objekt ist, können Sie .equals() oder .hashCode() nicht aufrufen, sodass Hashtable keinen Hash berechnen kann, um ihn als Schlüssel zu verwenden.

37
Jainendra

Der Hauptgrund, warum Hashtable und ConcurrentHashMap keine Nullschlüssel oder -werte zulassen, liegt in der Erwartung, dass sie in einer Multithread-Umgebung verwendet werden. Nehmen wir einmal an, dass Nullwerte zulässig sind. In diesem Fall hat die get-Methode ein mehrdeutiges Verhalten. Es kann Null zurückgeben, wenn der Schlüssel nicht in der Map gefunden wird, oder Null, wenn der Schlüssel gefunden wird und dessen Wert Null ist. Wenn ein Code NULL-Werte erwartet, prüft er normalerweise, ob der Schlüssel in der Map vorhanden ist, sodass er wissen kann, ob der Schlüssel nicht vorhanden ist oder der Schlüssel vorhanden ist, der Wert jedoch NULL ist. Jetzt bricht dieser Code in einer Umgebung mit mehreren Threads. Schauen wir uns den Code unten an:

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

Nehmen wir an, der Thread t1 ruft in dem obigen Code die enthaltende Methode auf und findet den Schlüssel. Dabei wird davon ausgegangen, dass der Schlüssel vorhanden ist und bereit ist, den Wert zurückzugeben, ob er null ist oder nicht. Vor dem Aufruf von map.get entfernt ein anderer Thread t2 diesen Schlüssel aus der Map. Jetzt wird t1 fortgesetzt und null zurückgegeben. Laut Code lautet die richtige Antwort für t1 jedoch KeyNotFoundException, da der Schlüssel entfernt wurde. Aber es gibt immer noch die Null zurück und somit ist das erwartete Verhalten gebrochen. 

Nun wird für eine reguläre HashMap davon ausgegangen, dass sie von einem einzelnen Thread aufgerufen wird. Daher besteht keine Möglichkeit, dass der Schlüssel in der Mitte von "enthält" überprüft und "abgerufen" wird. Daher kann HashMap Nullwerte tolerieren. Für Hashtable und ConcurrentHashMap ist jedoch klar, dass mehrere Threads die Daten beeinflussen werden. Daher können sie es sich nicht leisten, Nullwerte zuzulassen und falsche Antworten zu geben. Gleiche Logik gilt für Schlüssel. Das Zählerargument kann nun Folgendes sein: Die Enthält- und Get-Schritte könnten für Nicht-Null-Werte für Hashtables und ConcurrentHashMaps fehlschlagen, da ein anderer Thread die Map/Tabelle ändern kann, bevor der zweite Schritt ausgeführt wird. Das ist richtig, es kann passieren. Da Hashtables und ConcurrentHashMaps jedoch keine Nullschlüssel und -werte zulassen, ist es nicht erforderlich, dass sie Containers implementieren und an erster Stelle prüfen. Sie können den Wert direkt abrufen, weil sie wissen, dass der Schlüssel nicht vorhanden ist, wenn die get-Methode null zurückgibt, und nicht, weil der Wert null sein kann. Die Enthält-und-Get-Überprüfung ist nur für HashMaps erforderlich, da sie die Nullwerte zulassen und daher die Mehrdeutigkeit darüber lösen müssen, ob der Schlüssel nicht gefunden wird oder ob der Wert Null ist. 

2
punitoza

Der Grund ist der Grund für die akzeptierte Antwort: Hashtable ist alt.

Die Verwendung von Hashtable IS wird jedoch in jedem Szenario NICHT zugunsten von HashMap empfohlen.

  • Hashtable ist synchronisiert, dh es ist THREAD-SAFE . HashMap ist nicht.

Weder Hashtable noch ConcurrentHashMap unterstützen Nullschlüssel oder -werte. HashMap macht.

Wenn Sie einen Drop-In-Ersatz benötigen, der nichts anderes erfordert, als die Klasse zu ändern und in jedem Szenario funktioniert, gibt es keinen. Die ähnlichste Option wäre ConcurrentHashMap (was Thread-sicher ist, aber das Sperren der gesamten Tabelle nicht unterstützt):

Diese Klasse ist mit Hashtable in Programmen, die auf .__ vertrauen, vollständig kompatibel. auf seinen Thread-Sicherheit, aber nicht auf die Synchronisationsdetails.

HashMap ist ein besserer Ersatz für Single-Threaded-Anwendungen oder es ist keine Zeitsynchronisierung erforderlich, da sich die Synchronisierung auf die Leistung auswirkt.

Quellen:

2
NotGaeL

Die Implementierung der Standard-Hashtable hat eine Nullprüfung, die die Ausnahme für den Nullzeiger durchführt. Später haben Java-Entwickler die Wichtigkeit von Nullschlüsseln (für einige Standardwerte usw.) und Werte erkannt und warum HashMap eingeführt wurde.

Bei HashMap gibt es eine Nullprüfung für Schlüssel. Wenn der Schlüssel Null ist, wird das Element an einem Ort gespeichert, an dem kein Hashcode erforderlich ist.

1
psl

Die Hashtabelle ist eine sehr alte Klasse von JDK 1.0

Um dies zu verstehen, müssen wir zunächst die Kommentare verstehen, die von author ..__ in dieser Klasse geschrieben wurden. “Diese Klasse implementiert eine Hashtabelle, die Schlüssel zu Werten abbildet. Jedes Objekt, das nicht Null ist, kann als Schlüssel oder als Wert verwendet werden. Zum erfolgreichen Speichern und Abrufen von Objekten aus einer Hashtabelle müssen die als Schlüssel verwendeten Objekte die HashCode-Methode und die equals-Methode implementieren. "

Die HashTable-Klasse ist auf einem Hash-Mechanismus implementiert, dh, um jedes Schlüssel-Wert-Paar zu speichern, ist der erforderliche Hash-Code des Schlüsselobjekts erforderlich. Wenn der Schlüssel null wäre, kann er keinen Hashwert angeben, er wird durch eine Nullzeigerausnahme und einen ähnlichen Fall für Wert .__ ausgeführt. Wenn der Wert null ist, wird Null ausgegeben.

Später wurde jedoch erkannt, dass der Schlüssel und der Wert des Nullwerts eine eigene Bedeutung haben. Dies ist der Grund, warum ein Nullschlüssel und mehrere Nullwerte in später implementierten Klassen wie der HashMap-Klasse zulässig sind.

Bei Hash-Map-Null-Schlüsseln ist dies zulässig, und für die Schlüssel gibt es eine Nullprüfung. Wenn der Schlüssel null ist, wird das Element an einer Nullstelle im Entry-Array gespeichert. NULL-Schlüssel können wir für einige Standardwerte verwenden ..

=> Hashtable-Methoden werden synchronisiert, da das objektbasierte Sperren nicht verwendet wird.

HashMap implementiert, indem es als speziell betrachtet wird

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

Java 8 Sie können keine Typen für Hashtabellen ableiten.

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

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

Genau wie @Jainendra gesagt hat, erlaubt HashTable keine Null-Taste für den Aufruf key.hashCode () in put().

Es scheint jedoch, dass niemand eindeutig antwortet, warum Nullwerte nicht zulässig sind.

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;
}

Das Einfügen des NULL-Checks erklärt nicht, warum der NULL-Wert illegal ist, sondern sorgt nur für eine Nicht-NULL-Invariante.

Die konkrete Antwort für einen nicht zulässigen Nullwert ist, dass HashTable value.equals aufruft, wenn contains/remove aufgerufen wird.

0
Jiacai Liu

so zu schließen

Weil in HashTable beim Einfügen eines Elements der Schlüssel und der Wertehash berücksichtigt werden. Im Grunde haben Sie so etwas wie:

public Object put(Object key, Object value){

    key.hashCode();

    //some code

    value.hashCode();

}

HashTable - Erlaubt keine NULL-Schlüssel Dies liegt daran, dass wir in der put (K-Schlüssel, V-Wert) -Methode key.hashcode () haben, die eine Nullzeiger-Ausnahme auslöst. Dies liegt daran, dass wir als put (K key, V value) -Methode if (value == null) {neue NullPointerException werfen

HashMap erlaubt Nullwerte, da es keine Prüfungen wie HashTable gibt, während es nur einen Nullschlüssel zulässt. Dies geschieht mit Hilfe der putForNullKey-Methode, die den Wert jedes Mal zum 0-ten Index des internen Arrays hinzufügt, wenn der Schlüssel als Null angegeben wird

0
Rehan