我一直在琢磨了一段时间是否是最好的做法中允许使用的不要containsKey()
的方法java.util.Map
,而是做的结果从一个空检查get()
。
我的理由是,它似乎是多余的做值的两倍查找-首先为containsKey()
然后再次get()
。
在另一方面,它可能是最标准实现Map
缓存最后查找或编译器可以以其他方式废除冗余,并且对于代码的可读性最好是保持containsKey()
的一部分。
我将非常感激您的意见。
我一直在琢磨了一段时间是否是最好的做法中允许使用的不要containsKey()
的方法java.util.Map
,而是做的结果从一个空检查get()
。
我的理由是,它似乎是多余的做值的两倍查找-首先为containsKey()
然后再次get()
。
在另一方面,它可能是最标准实现Map
缓存最后查找或编译器可以以其他方式废除冗余,并且对于代码的可读性最好是保持containsKey()
的一部分。
我将非常感激您的意见。
一些map的实现被允许为空值,例如HashMap的,在这种情况下,如果get(key)
返回null
但不保证不存在与该键关联的地图没有条目。
所以,如果你想知道如果地图包含密钥使用Map.containsKey
。 如果你只需要映射到一个键使用值Map.get(key)
。 如果此映射允许空值,则返回null值并不一定表明该映射不包含该键的映射关系; 在这种情况下Map.containsKey
是无用的,会影响性能。 此外,在一个地图(如并发访问情况ConcurrentHashMap
),你测试后Map.containsKey(key)
有机会的话,该条目将被另一个线程删除打电话之前Map.get(key)
。
我认为这是相当标准的写:
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
}
它不是的可读性和效率更高一点,所以我看不出有任何理由不这样做。 显然,如果你的地图可以包含空值,这两个选项不具有相同的语义 。
作为assylias表示,这是一个语义问题。 一般来说,Map.get(X)== null是你想要的,但也有它在哪里使用的containsKey重要案件。
一个这样的情况下是一个高速缓存。 我曾经在一个web应用程序这是查询其数据库经常寻找根本不存在的实体上的工作性能问题。 当我研究了缓存代码,该组件,我意识到这是查询数据库,如果cache.get(键)==空。 如果数据库中返回NULL(实体未找到),我们将缓存该键 - >空映射。
切换到的containsKey解决了这个问题,因为一个映射到一个空值实际上意味着什么。 键映射为null具有比不存在该键的不同语义。
我们可以@assylias回答与Java8可选更具可读性,
Optional.ofNullable(map.get(key)).ifPresent(value -> {
//do something with value
};)
在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);
}
containsKey
后跟一个get
是多余的,只有当我们知道先验NULL值永远不会被允许。 如果空值是无效的调用containsKey
有一个不平凡的性能损失,是刚刚开销如下所示标杆。
Java的8 Optional
成语- Optional.ofNullable(map.get(key)).ifPresent
或Optional.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
https://github.com/openjdk-mirror/jdk7u-jdk/blob/master/src/share/classes/java/util/TreeMap.java
https://github.com/openjdk-mirror/jdk7u-jdk/blob/master/src/share/classes/java/util/HashMap.java