HashMap 中的键是否存在检查

问题描述 投票:0回答:12

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

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

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

[更新] 我的 HashMap 中没有空值。

java hashmap
12个回答
586
投票

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

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

77
投票

通过检查密钥是否存在你不会获得任何东西。这是

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源代码。


资源:


58
投票

更好的方法是使用

containsKey
HashMap
方法。明天有人会将 null 添加到 Map 中。您应该区分密钥存在和密钥具有空值。


29
投票

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

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

到处都是?然后你应该简单地检查

map.get(key)
是否返回 null ,仅此而已。 顺便说一句,HashMap 不会因缺少键而抛出异常,而是返回 null。唯一需要
containsKey
的情况是当您存储空值时,以区分空值和缺失值,但这通常被认为是不好的做法。


9
投票

为了清楚起见,请使用

containsKey()
。它速度很快,并且保持代码干净和可读。
HashMap
的全部要点是键查找速度很快,只需确保
hashCode()
equals()
正确实现即可。


5
投票

您还可以使用 computeIfAbsent()

 类中的 
HashMap
 方法。 

在以下示例中,

map
存储应用于密钥(银行帐户名称)的交易(整数)列表。要将
100
200
的 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()
    将返回键的值。

真的很优雅! 👍


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

1
投票

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

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

0
投票

我通常使用这个习语

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

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


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

0
投票

Jon Skeet 的答案以有效的方式很好地解决了两种情况(使用

null
值映射而不是
null
值)。

关于数量条目和效率问题,我想补充一下。

我有一个 HashMap,其中有 1000 个条目,我正在考虑改进 效率。如果HashMap被频繁访问,那么 每次访问时检查密钥是否存在将导致大量 开销。

包含 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
,则可能会发生一些碰撞,但
Map
中的对象数量从一千到数千个,您应该拥有很少的数据,因为
String.hashCode()
方法提供了良好的分布。

如果您使用自定义类型,请正确覆盖

hashCode()
equals()
,并确保总体上
hashCode()
提供公平的分配。
你可以参考
Java Effective
第9项提到的。
这是一篇post,详细介绍了方法。


0
投票

如果地图不包含我们要查找的键,map.get(key)将返回null。下面的代码块将返回 Key : null

    Map<String,String> map = new HashMap<>();
    map.put("a","A");
    System.out.println("Key : " +map.get("b"));
© www.soinside.com 2019 - 2024. All rights reserved.