Je me demande depuis un certain temps s'il est permis, dans les meilleures pratiques, de s'abstenir d'utiliser la containsKey()
méthode java.util.Map
et de faire une vérification nulle sur le résultat de get()
.
Mon raisonnement est qu'il semble redondant de faire la recherche de la valeur deux fois - d'abord pour le containsKey()
, puis à nouveau pour get()
.
D'un autre côté, il se peut que la plupart des implémentations standard mettent en Map
cache la dernière recherche ou que le compilateur puisse autrement supprimer la redondance, et que pour la lisibilité du code, il est préférable de maintenir la containsKey()
partie.
J'apprécierais beaucoup vos commentaires.
la source
null
, voulez-vous traiter cela différemment en une clé / valeur qui n'est pas définie? Si vous n'avez pas spécifiquement besoin de le traiter différemment, vous pouvez simplement utiliserget()
Map
c'est le casprivate
, votre classe pourra peut-être garantir qu'unnull
n'est jamais inséré dans la carte. Dans ce cas, vous pouvez utiliserget()
suivi d'une vérification de null au lieu decontainsKey()
. Cela peut être plus clair, et peut-être un peu plus efficace, dans certains cas.Je pense que c'est assez standard d'écrire:
au lieu de
Ce n'est pas moins lisible et un peu plus efficace donc je ne vois aucune raison de ne pas le faire. Évidemment, si votre carte peut contenir null, les deux options n'ont pas la même sémantique .
la source
Comme l'a indiqué assylias, c'est une question sémantique. Généralement, Map.get (x) == null est ce que vous voulez, mais il y a 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 performances dans une application Web qui interrogeait fréquemment sa base de données à la recherche d'entités qui n'existaient pas. Lorsque j'ai étudié le code de mise en cache pour ce composant, j'ai réalisé qu'il interrogeait la base de données si cache.get (clé) == null. Si la base de données renvoyait null (entité non trouvée), nous mettrions en cache cette clé -> mappage nul.
Le passage à containsKey a résolu le problème car un mappage à une valeur nulle signifiait en fait quelque chose. Le mappage de clé à null avait une signification sémantique différente de celle de la clé inexistante.
la source
containsKey
suivi de aget
n'est redondant que si nous savons apriori que les valeurs nulles ne seront jamais autorisées. Si les valeurs nulles ne sont pas valides, l'appel decontainsKey
a une pénalité de performances non négligeable et est juste une surcharge, comme indiqué dans le test ci-dessous.Les
Optional
idiomes Java 8 -Optional.ofNullable(map.get(key)).ifPresent
ouOptional.ofNullable(map.get(key)).ifPresent
- entraînent une surcharge non triviale par rapport aux vérifications nulles simples.A
HashMap
utilise uneO(1)
recherche de table constante tandis que aTreeMap
utilise uneO(log(n))
recherche. LecontainsKey
suivi d'unget
idiome est beaucoup plus lent lorsqu'il est invoqué sur unTreeMap
.Benchmarks
Voir https://github.com/vkarun/enum-reverse-lookup-table-jmh
Référence source TreeMap
https://github.com/openjdk-mirror/jdk7u-jdk/blob/master/src/share/classes/java/util/TreeMap.java
Référence de la source HashMap
https://github.com/openjdk-mirror/jdk7u-jdk/blob/master/src/share/classes/java/util/HashMap.java
la source
Nous pouvons rendre la réponse @assylias plus lisible avec Java8 facultatif,
la source
En Java si vous vérifiez l'implémentation
les deux utilisent getNode pour récupérer la correspondance, là 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 souhaitez récupérer la signification d'un mot
Faire...
est redondant.
mais si vous voulez vérifier qu'un mot est valide ou non basé sur le dictionnaire. Faire...
plus de...
est redondant.
Si vous vérifiez l' implémentation de HashSet , qui utilise HashMap en interne, utilisez 'containsKey' dans la méthode 'contains'.
la source