HashMap的key和value可以为空,ConcurrentHashMap和HashTable不可以,为什么

应用场景

HashMap是线程不安全的,所以应用于单线程场景下
ConcurrentHashMap和HashTable是线程安全的,应用于多线程场景下

出现区别的原因

当调用get(key)时,若返回的value为空,能不能确定这个value是存的是null还是因为没有这个key返回的null。

原因

HashMap

因为HashMap是应用在单线程场景下,在源码中,当判断key为空时,会把value存入table[0]处。
当value为空时,可以通过**containsKey(key)**来判断是否有key,若有,则说明返回的null是空value,若没有这个key,则说明返回的null是没有这个key的空。
当存入key和value的都为空时,containskey(key)也会返回true,以为table中有Node节点(Node中的key和value属性都为null)

HashTable和concurrentHashmap

因为这两个集合是应用于多线程场景下,在使用containsKey(key)和get(key)两个方法期间,可能存在其他线程对key的value进行修改,这样,当containsKey(key)返回true后,另一个线程将key删除,这时在get(key)返回的null代表的是没有这个key,但线程却以为是value为空,出现矛盾。

置于为什么key不能为null,可能是为了对应value把,既然value不能为null了,key也不要为null了,以免出现什么不可预料的异常。
(源码就是这样,没有发现有什么具体原因,如果有,欢迎大佬可以提出)

代码

import java.util.HashMap;
import java.util.concurrent.ConcurrentHashMap;

public class TestMap {
    public static void main(String[] args){
        HashMap<Integer,Integer> map = new HashMap<>();
        System.out.println(map.containsKey(null));
        System.out.println(map.get(null));

        map.put(null,null);//当key为空时,key的hash值为0
        System.out.println(map.containsKey(null));
        System.out.println(map.get(null));

        map.put(null,123);
        System.out.println(map.containsKey(null));
        System.out.println(map.get(null));

        ConcurrentHashMap<Integer,Integer> cmap = new ConcurrentHashMap<>();
        System.out.println(cmap.containsKey(null));
        System.out.println(cmap.get(null));

        cmap.put(null,123);
        cmap.put(123,null);

    }
}

输出:从containsKey(key)处就开始异常。

false
null
true
null
true
123
Exception in thread “main” java.lang.NullPointerException
at java.util.concurrent.ConcurrentHashMap.get(ConcurrentHashMap.java:936)
at java.util.concurrent.ConcurrentHashMap.containsKey(ConcurrentHashMap.java:964)
at TestMap.main(TestMap.java:21)
Process finished with exit code 1

你可能感兴趣的:(java,hashmap)