简体   繁体   English

密钥存在检查 HashMap

[英]Key existence check in HashMap

Is checking for key existence in HashMap always necessary?是否始终需要检查 HashMap 中是否存在密钥?

I have a HashMap with say a 1000 entries and I am looking at improving the efficiency.我有一个 HashMap,比如有 1000 个条目,我正在考虑提高效率。 If the HashMap is being accessed very frequently, then checking for the key existence at every access will lead to a large overhead.如果 HashMap 的访问非常频繁,那么每次访问都要检查 key 是否存在会导致很大的开销。 Instead if the key is not present and hence an exception occurs, I can catch the exception.相反,如果密钥不存在并因此发生异常,我可以捕获异常。 (when I know that this will happen rarely). (当我知道这种情况很少发生时)。 This will reduce accesses to the HashMap by half.这将使对 HashMap 的访问减少一半。

This might not be a good programming practice, but it will help me reduce the number of accesses.这可能不是一个好的编程习惯,但它会帮助我减少访问次数。 Or am I missing something here?还是我在这里遗漏了什么?

[ Update ] I do not have null values in the HashMap. [更新] 我在 HashMap 中没有 null 值。

Do you ever store a null value? 你有没有存储空值? If not, you can just do: 如果没有,你可以这样做:

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

Otherwise, you could just check for existence if you get a null value returned: 否则,如果返回null值,则可以检查是否存在:

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

You won't gain anything by checking that the key exists. 通过检查密钥是否存在,您将无法获得任何收益。 This is the code of HashMap : 这是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;
}

Just check if the return value for get() is different from null . 只需检查get()的返回值是否与null不同。

This is the HashMap source code. 这是HashMap源代码。


Resources : 资源:

Better way is to use containsKey method of HashMap . 更好的方法是使用HashMap containsKey方法。 Tomorrow somebody will add null to the Map. 明天有人会向地图添加null。 You should differentiate between key presence and key has null value. 您应该区分密钥存在和密钥具有空值。

Do you mean that you've got code like 你是说你有像这样的代码

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

all over the place ? 到处都是 ? Then you should simply check whether map.get(key) returned null and that's it. 然后你应该简单地检查map.get(key)是否返回null,就是这样。 By the way, HashMap doesn't throw exceptions for missing keys, it returns null instead. 顺便说一下,HashMap不会为丢失的密钥抛出异常,而是返回null。 The only case where containsKey is needed is when you're storing null values, to distinguish between a null value and a missing value, but this is usually considered bad practice. 需要containsKey的唯一情况是当你存储空值时,要区分空值和缺失值,但这通常被认为是不好的做法。

Just use containsKey() for clarity. 为清楚起见,只需使用containsKey() It's fast and keeps the code clean and readable. 它速度快,保持代码清洁和可读性。 The whole point of HashMap s is that the key lookup is fast, just make sure the hashCode() and equals() are properly implemented. HashMap的重点是密钥查找速度快,只需确保正确实现hashCode()equals()

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

You can also use the computeIfAbsent() method in the HashMap class. 您还可以在HashMap类中使用computeIfAbsent()方法。

In the following example, map stores a list of transactions (integers) that are applied to the key (the name of the bank account). 在以下示例中, map存储应用于密钥的事务(整数)列表(银行帐户的名称)。 To add 2 transactions of 100 and 200 to checking_account you can write: 要向checking_account添加2个100200事务,您可以编写:

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

This way you don't have to check to see if the key checking_account exists or not. 这样您就不必检查密钥checking_account存在。

  • If it does not exist, one will be created and returned by the lambda expression. 如果它不存在,将由lambda表达式创建并返回一个。
  • If it exists, then the value for the key will be returned by computeIfAbsent() . 如果存在,则computeIfAbsent()将返回键的值。

Really elegant! 真的很优雅! 👍 👍

I usually use the idiom 我通常使用这个成语

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

This means you only hit the map twice if the key is missing 这意味着如果缺少密钥,则只会按两次地图

  1. If key class is your's make sure the hashCode() and equals() methods implemented. 如果是关键类,请确保实现了hashCode()和equals()方法。
  2. Basically the access to HashMap should be O(1) but with wrong hashCode method implementation it's become O(n), because value with same hash key will stored as Linked list. 基本上,对HashMap的访问应该是O(1),但是使用错误的hashCode方法实现它变为O(n),因为具有相同散列键的值将存储为链接列表。

The Jon Skeet answer addresses well the two scenarios (map with null value and not null value) in an efficient way. Jon Skeet的答案很好地解决了两种情况(使用null值映射而非null值)。

About the number entries and the efficiency concern, I would like add something. 关于数字条目和效率问题,我想补充一些东西。

I have a HashMap with say a 1.000 entries and I am looking at improving the efficiency. 我有一个HashMap,说有1000个条目,我正在寻求提高效率。 If the HashMap is being accessed very frequently, then checking for the key existence at every access will lead to a large overhead. 如果非常频繁地访问HashMap,那么在每次访问时检查密钥是否存在将导致很大的开销。

A map with 1.000 entries is not a huge map. 包含1.000个条目的地图不是一张巨大的地图。
As well as a map with 5.000 or 10.000 entries. 以及具有5.000或10.000条目的地图。
Map are designed to make fast retrieval with such dimensions. Map旨在使这种尺寸快速检索。

Now, it assumes that hashCode() of the map keys provides a good distribution. 现在,它假设map键的hashCode()提供了良好的分布。

If you may use an Integer as key type, do it. 如果您可以使用Integer作为密钥类型,请执行此操作。
Its hashCode() method is very efficient since the collisions are not possible for unique int values : 它的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;
    }
    ...
}

If for the key, you have to use another built-in type as String for example that is often used in Map , you may have some collisions but from 1 thousand to some thousands of objects in the Map , you should have very few of it as the String.hashCode() method provides a good distribution. 如果为重点,你必须使用另一种内置类型String ,例如,往往是在使用Map ,你可能会有一些冲突,但在1万到几千中的对象的Map ,你应该很少吧因为String.hashCode()方法提供了良好的分布。

If you use a custom type, override hashCode() and equals() correctly and ensure overall that hashCode() provides a fair distribution. 如果使用自定义类型,请正确覆盖hashCode()equals() ,并确保hashCode()提供公平分配。
You may refer to the item 9 of Java Effective refers it. 您可以参考Java Effective 9项Java Effective引用它。
Here's a post that details the way. 这是一篇详细说明方式的帖子

Since java 1.8, you can simply use:从 java 1.8 开始,您可以简单地使用:

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

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM