L’utilisation de java Map.containsKey () est-elle redondante lors de l’utilisation de map.get ()?

Je me demande depuis un certain temps s’il est permis, dans la meilleure pratique, de ne pas utiliser la méthode containsKey() sur java.util.Map et de vérifier à la place le résultat de get() .

Ma raison est que cela semble redondant de faire la recherche de la valeur deux fois – d’abord pour containsKey() et puis à nouveau pour get() .

D’un autre côté, il se peut que la plupart des implémentations standard de Map cache la dernière recherche ou que le compilateur puisse supprimer la redondance, et que pour la lisibilité du code, il est préférable de conserver la partie containsKey() .

J’apprécierais beaucoup vos commentaires.

Certaines implémentations Map peuvent avoir des valeurs nulles, par exemple HashMap, dans ce cas, si get(key) renvoie null cela ne garantit pas qu’il n’y a pas d’entrée dans la carte associée à cette clé.

Donc, si vous voulez savoir si une carte contient une clé, utilisez Map.containsKey . Si vous avez simplement besoin d’une valeur mappée sur une clé, utilisez Map.get(key) . Si cette carte autorise des valeurs nulles, une valeur de retour de null n’indique pas nécessairement que la carte ne contient aucun mappage pour la clé. Dans ce cas, Map.containsKey est inutile et affectera les performances. De plus, en cas d’access simultané à une carte (par exemple ConcurrentHashMap ), après avoir testé Map.containsKey(key) il est possible que l’entrée soit supprimée par un autre thread avant d’appeler Map.get(key) .

Je pense qu’il est assez standard d’écrire:

 Object value = map.get(key); if (value != null) { //do something with value } 

au lieu de

 if (map.containsKey(key)) { Object value = map.get(key); //do something with value } 

Ce n’est pas moins lisible et légèrement plus efficace, donc je ne vois aucune raison de ne pas le faire. Évidemment, si votre map peut contenir null, les deux options n’ont pas la même sémantique .

Comme l’indiquent les assylias, il s’agit d’une question sémantique. En général, Map.get (x) == null est ce que vous voulez, mais il existe des cas où il est important d’utiliser containsKey.

Un tel cas est un cache. J’ai déjà travaillé sur un problème de performance dans une application Web qui interrogeait fréquemment sa firebase database à la recherche d’entités inexistantes. Lorsque j’ai étudié le code de mise en cache pour ce composant, j’ai réalisé qu’il interrogeait la firebase database si cache.get (key) == null. Si la firebase database renvoyait null (entité non trouvée), nous metsortingons en cache cette clé -> mappage nul.

Passer à containsKey a résolu le problème car un mappage sur une valeur nulle signifiait en fait quelque chose. Le mappage de la clé sur null avait une signification sémantique différente de celle de la clé inexistante.

Nous pouvons rendre @assylias plus lisible avec Java8 Facultatif,

 Optional.ofNullable(map.get(key)).ifPresent(value -> { //do something with value };) 

En Java si vous vérifiez l’implémentation

 public boolean containsKey(Object key) { return getNode(hash(key), key) != null; } public V get(Object key) { Node e; return (e = getNode(hash(key), key)) == null ? null : e.value; } 

Les deux utilisent getNode pour récupérer la correspondance, où le travail principal est effectué.

la redondance est contextuelle, par exemple si vous avez un dictionnaire stocké dans une carte de hachage. Lorsque vous voulez récupérer le sens d’un mot

Faire…

 if(dictionary.containsKey(word)) { return dictionary.get(word); } 

est redondant.

mais si vous voulez vérifier un mot est valide ou non basé sur le dictionnaire. Faire…

  return dictionary.get(word) != null; 

plus de…

  return dictionary.containsKey(word); 

est redondant.

Si vous vérifiez l’implémentation de HashSet , qui utilise HashMap en interne, utilisez la méthode ‘containsKey’ dans ‘contains’.

  public boolean contains(Object o) { return map.containsKey(o); }