web-dev-qa-db-fra.com

Vérification de l'existence d'une clé dans HashMap

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.

270
athena

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
    }
}
466
Jon Skeet

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 :

63
Colin Hebert

Mieux vaut utiliser la méthode containsKey de HashMap. Demain, soembody ajoutera null à la carte, vous devez différencier clé et valeur nulle.

38
Dead Programmer

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.

22
jkff

Utilisez simplement containsKey() pour plus de clarté. C'est rapide et garde le code propre et lisible. L’intérêt de HashMaps est que la recherche de clé est rapide, assurez-vous simplement que les fonctions hashCode() et equals() sont correctement implémentées.

6
Mikko Wilkman
if(map.get(key) != null || (map.get(key) == null && map.containsKey(key)))
4
Erlan

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.

0
davidxxx

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.

0
Jon Freedman
  1. Si la classe clé vous appartient, assurez-vous que les méthodes hashCode () et equals () sont implémentées.
  2. En gros, l'accès à HashMap devrait être O(1), mais avec une implémentation incorrecte de la méthode hashCode, il est devenu O (n), car la valeur avec la même clé de hachage sera stockée en tant que liste liée.
0
Boris

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.

  • S'il n'existe pas, il sera créé et renvoyé par l'expression lambda. 
  • S'il existe, la valeur de la clé sera renvoyée par computeIfAbsent()

Vraiment élégant! ????

0
nazmul idris