使用map.get时是用Java Map.containsKey()多余的()(Is using j

2019-07-19 00:04发布

我一直在琢磨了一段时间是否是最好的做法中允许使用的不要containsKey()的方法java.util.Map ,而是做的结果从一个空检查get()

我的理由是,它似乎是多余的做值的两倍查找-首先为containsKey()然后再次get()

在另一方面,它可能是最标准实现Map缓存最后查找或编译器可以以其他方式废除冗余,并且对于代码的可读性最好是保持containsKey()的一部分。

我将非常感激您的意见。

Answer 1:

一些map的实现被允许为空值,例如HashMap的,在这种情况下,如果get(key)返回null但不保证不存在与该键关联的地图没有条目。

所以,如果你想知道如果地图包含密钥使用Map.containsKey 。 如果你只需要映射到一个键使用值Map.get(key) 。 如果此映射允许空值,则返回null值并不一定表明该映射不包含该键的映射关系; 在这种情况下Map.containsKey是无用的,会影响性能。 此外,在一个地图(如并发访问情况ConcurrentHashMap ),你测试后Map.containsKey(key)有机会的话,该条目将被另一个线程删除打电话之前Map.get(key)



Answer 2:

我认为这是相当标准的写:

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

代替

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

它不是的可读性和效率更高一点,所以我看不出有任何理由不这样做。 显然,如果你的地图可以包含空值,这两个选项不具有相同的语义



Answer 3:

作为assylias表示,这是一个语义问题。 一般来说,Map.get(X)== null是你想要的,但也有它在哪里使用的containsKey重要案件。

一个这样的情况下是一个高速缓存。 我曾经在一个web应用程序这是查询其数据库经常寻找根本不存在的实体上的工作性能问题。 当我研究了缓存代码,该组件,我意识到这是查询数据库,如果cache.get(键)==空。 如果数据库中返回NULL(实体未找到),我们将缓存该键 - >空映射。

切换到的containsKey解决了这个问题,因为一个映射到一个空值实际上意味着什么。 键映射为null具有比不存在该键的不同语义。



Answer 4:

我们可以@assylias回答与Java8可选更具可读性,

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


Answer 5:

在Java中,如果你检查的实施

public boolean containsKey(Object key) {
    return getNode(hash(key), key) != null;
}

public V get(Object key) {
    Node<K,V> e;
    return (e = getNode(hash(key), key)) == null ? null : e.value;
}

两者都使用getNode检索匹配,这里主要完成工作。

冗余例如,如果您有存储在一个哈希表的字典的语境。 当你想查询某个英文单词的含义

做...

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

是多余的。

但如果你想检查一个单词是否有效基于字典。 做...

 return dictionary.get(word) != null;

过度...

 return dictionary.containsKey(word);

是多余的。

如果您检查HashSet的实现,它使用HashMap的内部,在使用“的containsKey“包含”方法。

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


Answer 6:

  • containsKey后跟一个get是多余的,只有当我们知道先验NULL值永远不会被允许。 如果空值是无效的调用containsKey有一个不平凡的性能损失,是刚刚开销如下所示标杆。

  • Java的8 Optional成语- Optional.ofNullable(map.get(key)).ifPresentOptional.ofNullable(map.get(key)).ifPresent -在比较招致一个不平凡的开销只是香草null检查。

  • HashMap使用O(1)恒定表查找而TreeMap使用O(log(n))查找。 该containsKey后跟一个get在调用时成语慢得多TreeMap

基准

见https://github.com/vkarun/enum-reverse-lookup-table-jmh

// t1
static Type lookupTreeMapNotContainsKeyThrowGet(int t) {
  if (!lookupT.containsKey(t))
    throw new IllegalStateException("Unknown Multihash type: " + t);
  return lookupT.get(t);
}
// t2
static Type lookupTreeMapGetThrowIfNull(int t) {
  Type type = lookupT.get(t);
  if (type == null)
    throw new IllegalStateException("Unknown Multihash type: " + t);
  return type;
}
// t3
static Type lookupTreeMapGetOptionalOrElseThrow(int t) {
  return Optional.ofNullable(lookupT.get(t)).orElseThrow(() -> new 
      IllegalStateException("Unknown Multihash type: " + t));
}
// h1
static Type lookupHashMapNotContainsKeyThrowGet(int t) {
  if (!lookupH.containsKey(t))
    throw new IllegalStateException("Unknown Multihash type: " + t);
  return lookupH.get(t);
}
// h2
static Type lookupHashMapGetThrowIfNull(int t) {
  Type type = lookupH.get(t);
  if (type == null)
    throw new IllegalStateException("Unknown Multihash type: " + t);
  return type;
}
// h3
static Type lookupHashMapGetOptionalOrElseThrow(int t) {
  return Optional.ofNullable(lookupH.get(t)).orElseThrow(() -> new 
    IllegalStateException("Unknown Multihash type: " + t));
}
Benchmark                                (iterations)  (lookupApproach)  Mode  Cnt   Score   Error  Units

MultihashTypeLookupBenchmark.testLookup          1000                t1  avgt    9  33.438 ± 4.514  us/op
MultihashTypeLookupBenchmark.testLookup          1000                t2  avgt    9  26.986 ± 0.405  us/op
MultihashTypeLookupBenchmark.testLookup          1000                t3  avgt    9  39.259 ± 1.306  us/op
MultihashTypeLookupBenchmark.testLookup          1000                h1  avgt    9  18.954 ± 0.414  us/op
MultihashTypeLookupBenchmark.testLookup          1000                h2  avgt    9  15.486 ± 0.395  us/op
MultihashTypeLookupBenchmark.testLookup          1000                h3  avgt    9  16.780 ± 0.719  us/op

TreeMap的源参考

https://github.com/openjdk-mirror/jdk7u-jdk/blob/master/src/share/classes/java/util/TreeMap.java

HashMap的源参考

https://github.com/openjdk-mirror/jdk7u-jdk/blob/master/src/share/classes/java/util/HashMap.java



文章来源: Is using java Map.containsKey() redundant when using map.get()