Est-il toujours nécessaire de vérifier l'existence d'une clé dans HashMap?
J'ai un HashMap avec, disons, 1 000 entrées et je cherche à améliorer l'efficacité . Si l'accès à HashMap est très fréquent, la vérification de l'existence de la clé à chaque accès entraînera une surcharge importante. Au lieu de cela, si la clé n'est pas présente et qu'une exception se produit, je peux attraper l'exception. (quand je sais que cela arrivera rarement). Cela réduira de moitié les accès à HashMap.
Ce n'est peut-être pas une bonne pratique de programmation, mais cela m'aidera à réduire le nombre d'accès. Ou est-ce que je manque quelque chose ici?
[ Update ] Je n'ai pas de valeurs NULL dans HashMap.
Avez-vous déjà stocké une valeur nulle? Sinon, vous pouvez simplement faire:
Foo value = map.get(key);
if (value != null) {
...
} else {
// No such key
}
Sinon, vous pourriez juste vérifier l'existence si vous obtenez une valeur null retournée:
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
}
}
Vous ne gagnerez rien en vérifiant que la clé existe. C'est le code de 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;
}
Il suffit de vérifier si la valeur de retour pour get()
est différente de null
.
C'est le code source de HashMap.
Ressources :
Mieux vaut utiliser la méthode containsKey de HashMap. Demain, soembody ajoutera null à la carte, vous devez différencier clé et valeur nulle.
Voulez-vous dire que vous avez un code comme
if(map.containsKey(key)) doSomethingWith(map.get(key))
partout ? Ensuite, vous devriez simplement vérifier si map.get(key)
a renvoyé la valeur null et le tour est joué. En passant, HashMap ne lève pas d'exceptions pour les clés manquantes, mais renvoie null. Le seul cas où containsKey
est nécessaire est lorsque vous stockez des valeurs NULL, afin de faire la distinction entre une valeur NULL et une valeur manquante, mais cela est généralement considéré comme une mauvaise pratique.
Utilisez simplement containsKey()
pour plus de clarté. C'est rapide et garde le code propre et lisible. L’intérêt de HashMap
s est que la recherche de clé est rapide, assurez-vous simplement que les fonctions hashCode()
et equals()
sont correctement implémentées.
if(map.get(key) != null || (map.get(key) == null && map.containsKey(key)))
La réponse de Jon Skeet traite bien les deux scénarios (carte avec la valeur null
et non la valeur null
) de manière efficace.
À propos du nombre d'entrées et du souci d'efficacité, j'aimerais ajouter quelque chose.
J'ai un HashMap avec disons 1.000 entrées et je cherche à améliorer l'efficacité. Si l'accès à HashMap est très fréquent, alors vérifier l'existence de la clé à chaque accès conduira à une grande aérien.
Une carte avec 1 000 entrées n'est pas une carte énorme.
Ainsi qu’une carte avec 5.000 ou 10.000 entrées.Map
sont conçus pour permettre une récupération rapide avec de telles dimensions.
Maintenant, il suppose que hashCode()
des touches de la carte fournit une bonne distribution.
Si vous pouvez utiliser une Integer
comme type de clé, faites-le.
Sa méthode hashCode()
est très efficace car les collisions ne sont pas possibles pour des valeurs int
uniques:
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;
}
...
}
Si pour la clé, vous devez utiliser un autre type prédéfini, par exemple String
qui est souvent utilisé dans Map
, vous pouvez avoir des collisions, mais entre 1 000 et quelques milliers d'objets dans la Map
, vous devriez en avoir très peu comme la méthode String.hashCode()
fournit une bonne distribution.
Si vous utilisez un type personnalisé, remplacez correctement hashCode()
et equals()
et assurez-vous que, globalement, hashCode()
fournit une distribution équitable.
Vous pouvez vous référer à l’article 9 du Java Effective
.
Voici un post qui détaille le chemin.
J'utilise habituellement l'idiome
Object value = map.get(key);
if (value == null) {
value = createValue(key);
map.put(key, value);
}
Cela signifie que vous n'appuyez sur la carte que deux fois si la clé est manquante.
Vous pouvez également utiliser la méthode computeIfAbsent()
dans la classe HashMap
.
Dans l'exemple suivant, map
stocke une liste de transactions (entiers) appliquées à la clé (nom du compte bancaire). Pour ajouter 2 transactions de 100
et 200
à checking_account
, vous pouvez écrire:
HashMap<String, ArrayList<Integer>> map = new HashMap<>();
map.computeIfAbsent("checking_account", key -> new ArrayList<>())
.add(100)
.add(200);
De cette façon, vous n'avez pas à vérifier si la clé checking_account
existe ou non.
computeIfAbsent()
. Vraiment élégant! ????