Eu estive me perguntando por algum tempo se é permitido, dentro das melhores práticas, evitar o uso do containsKey()
método emjava.util.Map
e, vez disso, fazer uma verificação nula no resultado de get()
.
Meu raciocínio é que parece redundante fazer a pesquisa do valor duas vezes - primeiro para o containsKey()
e depois novamente para get()
.
Por outro lado, pode ser que a maioria das implementações padrão de Map
cache da última consulta ou que o compilador possa eliminar a redundância e que, para legibilidade do código, seja preferível manter a containsKey()
parte.
Eu apreciaria muito seus comentários.
fonte
null
, você deseja tratar isso de forma diferente para uma chave / valor que não está definido? Se você não precisa especificamente tratá-lo de maneira diferente, você pode apenas usarget()
Map
forprivate
, sua classe pode garantir que anull
nunca seja inserido no mapa. Nesse caso, você poderia usarget()
seguido por uma verificação de nulo em vez decontainsKey()
. Isso pode ser mais claro e talvez um pouco mais eficiente em alguns casos.Acho que é bastante normal escrever:
ao invés de
Não é menos legível e um pouco mais eficiente, então não vejo motivos para não fazê-lo. Obviamente, se seu mapa pode conter nulo, as duas opções não têm a mesma semântica .
fonte
Como indicaram as assilias, esta é uma questão semântica. Geralmente, Map.get (x) == null é o que você deseja, mas há casos em que é importante usar containsKey.
Um desses casos é um cache. Certa vez, trabalhei em um problema de desempenho em um aplicativo da web que consultava seu banco de dados com frequência em busca de entidades que não existiam. Quando estudei o código de cache para esse componente, percebi que ele estava consultando o banco de dados se cache.get (key) == null. Se o banco de dados retornasse nulo (entidade não encontrada), armazenaríamos em cache essa chave -> mapeamento nulo.
Mudar para containsKey resolveu o problema porque um mapeamento para um valor nulo realmente significava algo. O mapeamento de chave para null tinha um significado semântico diferente do da chave não existente.
fonte
containsKey
seguido por aget
é redundante apenas se soubermos a priori que valores nulos nunca serão permitidos. Se os valores nulos não forem válidos, a invocação decontainsKey
tem uma penalidade de desempenho não trivial e é apenas uma sobrecarga, conforme mostrado no benchmark abaixo.Os
Optional
idiomas do Java 8 -Optional.ofNullable(map.get(key)).ifPresent
ouOptional.ofNullable(map.get(key)).ifPresent
- incorrem em uma sobrecarga não trivial em comparação com verificações de nulos simples.A
HashMap
usa umaO(1)
pesquisa de tabela constante, enquanto aTreeMap
usa umaO(log(n))
pesquisa. OcontainsKey
seguido por umget
idioma é muito mais lento quando invocado em aTreeMap
.Benchmarks
Veja https://github.com/vkarun/enum-reverse-lookup-table-jmh
Referência de fonte TreeMap
https://github.com/openjdk-mirror/jdk7u-jdk/blob/master/src/share/classes/java/util/TreeMap.java
Referência de fonte HashMap
https://github.com/openjdk-mirror/jdk7u-jdk/blob/master/src/share/classes/java/util/HashMap.java
fonte
Podemos tornar a resposta @assylias mais legível com Java8 opcional,
fonte
Em Java, se você verificar a implementação
ambos usam getNode para recuperar a correspondência, onde o trabalho principal é feito.
a redundância é contextual, por exemplo, se você tiver um dicionário armazenado em um mapa hash. Quando você deseja recuperar o significado de uma palavra
fazendo ...
é redundante.
mas se você quiser verificar se uma palavra é válida ou não com base no dicionário. fazendo ...
sobre...
é redundante.
Se você verificar a implementação de HashSet , que usa HashMap internamente, use 'containsKey' no método 'contém'.
fonte