Ist die Überprüfung der Existenz von Schlüsseln in HashMap immer erforderlich?
Ich habe eine HashMap mit etwa 1000 Einträgen und möchte die Effizienz verbessern. Wenn auf die HashMap sehr häufig zugegriffen wird, führt die Überprüfung der Existenz der Schlüssel bei jedem Zugriff zu einem großen Overhead. Wenn der Schlüssel nicht vorhanden ist und daher eine Ausnahme auftritt, kann ich die Ausnahme feststellen. (Wenn ich weiß, dass dies selten vorkommt). Dadurch werden die Zugriffe auf die HashMap um die Hälfte reduziert.
Dies ist möglicherweise keine gute Programmierpraxis, aber es hilft mir, die Anzahl der Zugriffe zu reduzieren. Oder fehlt mir hier etwas?
[ Update ] Ich habe keine Nullwerte in der HashMap.
Speichern Sie jemals einen Nullwert? Wenn nicht, können Sie einfach Folgendes tun:
Foo value = map.get(key);
if (value != null) {
...
} else {
// No such key
}
Andernfalls prüfen Sie (könnten auf Existenz prüfen, wenn Sie einen Nullwert zurückgeben:
Foo value = map.get(key);
if (value != null) {
...
} else {
// Key might be present...
if (map.containsKey(key)) {
// Okay, there's a key but the value is null
} else {
// Definitely no such key
}
}
Sie erhalten nichts, wenn Sie prüfen, ob der Schlüssel existiert. Dies ist der Code von HashMap
:
@Override
public boolean containsKey(Object key) {
Entry<K, V> m = getEntry(key);
return m != null;
}
@Override
public V get(Object key) {
Entry<K, V> m = getEntry(key);
if (m != null) {
return m.value;
}
return null;
}
Prüfen Sie einfach, ob sich der Rückgabewert für get()
von null
unterscheidet.
Dies ist der HashMap-Quellcode.
Ressourcen:
Besser ist es, diehälfteKey-Methode von HashMap zu verwenden. Morgen fügt die Person null zur Karte hinzu. Sie sollten zwischen dem Schlüssel dort und dem Schlüssel mit dem Wert null unterscheiden.
Meinen Sie, dass Sie Code wie haben
if(map.containsKey(key)) doSomethingWith(map.get(key))
überall ? Dann sollten Sie einfach prüfen, ob map.get(key)
null zurückgegeben hat und das wars. Übrigens wirft HashMap keine Ausnahmen für fehlende Schlüssel, sondern gibt stattdessen null zurück. Der einzige Fall, in dem containsKey
benötigt wird, ist das Speichern von Nullwerten, um zwischen einem Nullwert und einem fehlenden Wert zu unterscheiden. Dies wird jedoch normalerweise als schlechte Praxis angesehen.
Verwenden Sie einfach containsKey()
zur Verdeutlichung. Es ist schnell und hält den Code sauber und lesbar. Der springende Punkt von HashMap
s ist, dass die Schlüsselsuche schnell ist. Stellen Sie nur sicher, dass hashCode()
und equals()
ordnungsgemäß implementiert sind.
if(map.get(key) != null || (map.get(key) == null && map.containsKey(key)))
Die Antwort von Jon Skeet adressiert die beiden Szenarien (Karte mit null
-Wert und nicht null
-Wert) auf effiziente Weise.
Über die Nummerneingaben und die Effizienzfrage möchte ich noch etwas hinzufügen.
Ich habe eine HashMap mit etwa 1.000 Einträgen und bin dabei, .__ zu verbessern. Die Effizienz. Wenn auf die HashMap sehr häufig zugegriffen wird, dann Die Überprüfung der Schlüsselexistenz bei jedem Zugriff führt zu einem großen Overhead.
Eine Karte mit 1.000 Einträgen ist keine große Karte.
Sowie eine Karte mit 5.000 oder 10.000 Einträgen.Map
sind so konzipiert, dass sie mit solchen Abmessungen schnell abgerufen werden können.
Nun wird davon ausgegangen, dass hashCode()
der Kartenschlüssel eine gute Verteilung liefert.
Wenn Sie eine Integer
als Schlüsseltyp verwenden können, tun Sie es.
Die Methode hashCode()
ist sehr effizient, da für eindeutige int
-Werte keine Kollisionen möglich sind:
public final class Integer extends Number implements Comparable<Integer> {
...
@Override
public int hashCode() {
return Integer.hashCode(value);
}
public static int hashCode(int value) {
return value;
}
...
}
Wenn Sie für den Schlüssel einen anderen integrierten Typ als String
verwenden müssen, der beispielsweise häufig in Map
verwendet wird, haben Sie zwar einige Kollisionen, aber in der Map
von eintausend bis zu einigen tausend Objekten, sollten Sie nur wenige davon haben da die String.hashCode()
-Methode eine gute Verteilung bietet.
Wenn Sie einen benutzerdefinierten Typ verwenden, überschreiben Sie hashCode()
und equals()
korrekt und stellen Sie sicher, dass hashCode()
eine faire Verteilung bietet.
Sie können sich auf den Punkt 9 von Java Effective
beziehen.
Hier ist ein Beitrag der den Weg beschreibt.
Ich benutze normalerweise die Redewendung
Object value = map.get(key);
if (value == null) {
value = createValue(key);
map.put(key, value);
}
Das bedeutet, dass Sie die Karte nur zweimal treffen, wenn der Schlüssel fehlt
Sie können auch die Methode computeIfAbsent()
in der Klasse HashMap
verwenden.
Im folgenden Beispiel speichert map
eine Liste von Transaktionen (Ganzzahlen), die auf den Schlüssel angewendet werden (der Name des Bankkontos). Um 2 Transaktionen von 100
und 200
zu checking_account
hinzuzufügen, können Sie schreiben:
HashMap<String, ArrayList<Integer>> map = new HashMap<>();
map.computeIfAbsent("checking_account", key -> new ArrayList<>())
.add(100)
.add(200);
Auf diese Weise müssen Sie nicht prüfen, ob der Schlüssel checking_account
vorhanden ist oder nicht.
computeIfAbsent()
zurückgegeben. Wirklich elegant! ????