HashMap中关键的存在检查

检查HashMap中关键的存在是否必要?

我有一个HashMap说1000条目,我正在提高效率。 如果HashMap被非常频繁地访问,那么在每次访问时检查密钥的存在将导致很大的开销。 相反,如果钥匙不存在,因此发生exception,我可以赶上例外。 (当我知道这很less会发生)。 这将使访问HashMap减less一半。

这可能不是一个好的编程习惯,但它会帮助我减less访问次数。 还是我在这里错过了什么?

[ 更新 ]在HashMap中没有空值。

你有没有存储空值? 如果没有,你可以做:

Foo value = map.get(key); if (value != null) { ... } else { // No such key } 

否则,如果返回空值,则可以检查是否存在:

 Foo value = map.get(key); if (value != null) { ... } else { // Key might be present... if (map.containsKey(key)) { // Okay, there's a key but the value is null } else { // Definitely no such key } } 

通过检查密钥是否存在,您将不会获得任何收益。 这是HashMap的代码:

 @Override public boolean containsKey(Object key) { Entry<K, V> m = getEntry(key); return m != null; } @Override public V get(Object key) { Entry<K, V> m = getEntry(key); if (m != null) { return m.value; } return null; } 

只要检查get()的返回值是否与null不同即可。

这是HashMap源代码。


资源:

  • HashMap源代码不好的一个
  • HashMap源代码好的一个

更好的方法是使用HashMap的containsKey方法。 明天将向地图添加空值,您应该区分键和空值。

你的意思是说你有类似的代码

if(map.containsKey(key)) doSomethingWith(map.get(key))

到处都是 ? 那么你应该简单地检查map.get(key)是否返回null,就是这样。 顺便说一下,HashMap不会抛出丢失键的exception,而是返回null。 唯一需要使用containsKey的情况是在存储空值时区分空值和缺失值,但这通常被认为是不好的做法。

 if(map.get(key) != null || (map.get(key) == null && map.containsKey(key))) 

为了清楚起见,只需使用containsKey() 。 这是快速的,并保持代码清洁和可读性。 HashMap的关键在于密钥查找速度很快,只要确保hashCode()equals()都正确实现。

我通常使用这个成语

 Object value = map.get(key); if (value == null) { value = createValue(key); map.put(key, value); } 

这意味着如果钥匙丢失,您只能点击地图两次

  1. 如果key类是你的确保hashCode()和equals()方法的实现。
  2. 基本上对HashMap的访问应该是O(1),但是用错误的hashCode方法实现它将变成O(n),因为具有相同散列键的值将被存储为链接列表。

Jon Skeet的回答很好地解决了两种情况(具有null值和非null值的映射)。

关于数字条目和效率问题,我想添加一些东西。

我有一个1.000条目的HashMap,我期待提高效率。 如果HashMap被非常频繁地访问,那么在每次访问时检查密钥的存在将导致很大的开销。

有1000个条目的地图不是一个巨大的地图。
以及具有5.000或10.000条目的地图。
Map的目的是使这种尺寸的快速检索。

现在,它假定hashCode()提供了一个很好的分布。

如果您可以使用Integer作为键types,那么执行此操作。
它的hashCode()方法非常高效,因为对于唯一的int值来说碰撞是不可能的:

 public final class Integer extends Number implements Comparable<Integer> { ... @Override public int hashCode() { return Integer.hashCode(value); } public static int hashCode(int value) { return value; } ... } 

如果是键值,则必须使用另一个内置types(例如Map经常使用的内置types),可能会有一些冲突,但在Map有一千到几千个对象,您应该只有很less的一些因为String.hashCode()方法提供了一个很好的分布。

如果使用自定义types, hashCode()正确覆盖hashCode()equals() ,并确保hashCode()提供了一个公平分配。
你可以参考Java Effective 9项Java Effective引用它。
这里有一个细节的方式。