HashMap中存在键检查

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

我有一个HashMap,有1000个条目,我正在考虑提高效率。 如果HashMap被非常频繁地访问,那么在每次访问时检查键是否存在将导致很大的开销。相反,如果键不存在,因此发生了异常,则可以捕获异常。(当我知道这种情况很少发生时)。这将减少访问HashMap的一半

这可能不是一个好的编程实践,但它将帮助我减少访问次数。还是我漏了什么?

[更新] HashMap中没有空值。

587241 次浏览

你曾经存储空值吗?如果没有,你可以这样做:

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
}
}

我通常使用成语

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

这意味着如果钥匙丢失,你只需要点击地图两次

你是说你有代码

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

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

通过检查密钥是否存在,您不会获得任何东西。这是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的源代码。


资源:

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

更好的方法是使用HashMapcontainsKey方法。明天有人会把null添加到Map中。您应该区分键是否存在和键是否有空值。

为了清楚起见,只需使用containsKey()。这是快速的,并保持代码干净和可读。__abc1的全部意义在于键查找是快速的,只要确保hashCode()equals()被正确实现即可。

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

乔恩·斯基特的回答以有效的方式很好地解决了两种情况(映射为null值而不是null值)

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

我有一个HashMap,有1.000个条目,我正在考虑改进 的效率。如果HashMap被频繁访问,那么 在每个访问处检查密钥是否存在将导致一个较大的 开销。< / p >

一个有1.000个条目的地图不是一个巨大的地图 以及一个有5.000或10.000个条目的地图

. Map被设计用于快速检索这样的维度

现在,它假设映射键的hashCode()提供了一个良好的分布。

如果你可以使用Integer作为键类型,那么就这样做 它的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;
}
...
}

如果对于键,你必须使用另一个内置类型作为String,例如,经常在Map中使用,你可能会有一些冲突,但从1000到数千个对象在Map中,你应该有很少的它,因为String.hashCode()方法提供了一个良好的分布

如果使用自定义类型,则正确重写hashCode()equals(),并总体上确保hashCode()提供了公平的分布 你可以参考Java Effective的第9项引用它 这里有一个帖子详细说明了方法

你也可以在HashMap类中使用computeIfAbsent()方法。

在下面的例子中,map存储了应用于密钥(银行帐户名称)的事务(整数)列表。要将100200的2个事务添加到checking_account中,你可以这样写:

HashMap<String, ArrayList<Integer>> map = new HashMap<>();
map.computeIfAbsent("checking_account", key -> new ArrayList<>())
.add(100)
.add(200);

这样你就不必检查键checking_account是否存在。

  • 如果它不存在,lambda表达式将创建一个并返回。
  • 如果存在,则该键的值将由computeIfAbsent()返回。

真正的优雅!👍

从java 1.8开始,你可以简单地使用:

var item = mapObject.getOrDefault(key, null);
if(item != null)