一、背景
以null为key调用ConcurrentHashMap的containsKey方法时报空指针错误。
java.lang.NullPointerException
at java.util.concurrent.ConcurrentHashMap.get(ConcurrentHashMap.java:936)
at java.util.concurrent.ConcurrentHashMap.containsKey(ConcurrentHashMap.java:964)
二、ConcurrentHashMap和HashMap的containsKey方法区别
Map接口中containsKey方法定义如下:
public interface Map<K,V> {
...
boolean containsKey(Object key);
...
}
containsKey方法接受一个Object类型的参数,因此所有类型的对象都可以作为containsKey方法的参数,甚至null,编译不会报错。但当Map接口的实现类中containsKey方法不接受null作为入参时,以null作为入参调用该方法将抛出NullPointerException。
ConcurrentHashMap和HashMap都实现了Map接口。
2.1、ConcurrentHashMap中的containsKey方法如下:
...
public boolean containsKey(Object key) {
return get(key) != null;
}
public V get(Object key) {
Node<K,V>[] tab; Node<K,V> e, p; int n, eh; K ek;
int h = spread(key.hashCode()); // key not null
if ((tab = table) != null && (n = tab.length) > 0 &&
(e = tabAt(tab, (n - 1) & h)) != null) {
if ((eh = e.hash) == h) {
if ((ek = e.key) == key || (ek != null && key.equals(ek)))
return e.val;
}
else if (eh < 0)
return (p = e.find(h, key)) != null ? p.val : null;
while ((e = e.next) != null) {
if (e.hash == h &&
((ek = e.key) == key || (ek != null && key.equals(ek))))
return e.val;
}
}
return null;
}
...
ConcurrentHashMap在调用containsKey方法时,会首取key的hashCode值,如果key为空,则会抛出NullPointerException。因此ConcurrentHashMap不能以null作为key。
2.2、HashMap中的containsKey方法如下:
...
public boolean containsKey(Object key) {
return getNode(hash(key), key) != null;
}
static final int hash(Object key) {
int h;
return (key == null) ? 0 : (h = key.hashCode()) ^ (h >>> 16);
}
final Node<K,V> getNode(int hash, Object key) {
Node<K,V>[] tab; Node<K,V> first, e; int n; K k;
// key can be null
if ((tab = table) != null && (n = tab.length) > 0 &&
(first = tab[(n - 1) & hash]) != null) {
if (first.hash == hash && // always check first node
((k = first.key) == key || (key != null && key.equals(k))))
return first;
if ((e = first.next) != null) {
if (first instanceof TreeNode)
return ((TreeNode<K,V>)first).getTreeNode(hash, key);
do {
if (e.hash == hash &&
((k = e.key) == key || (key != null && key.equals(k))))
return e;
} while ((e = e.next) != null);
}
}
return null;
}
...
HashMap中定义了hash方法,该方法入参为null时返回0。因此HashMap可以null作为key。HashMap是在put元素后分配空间,HashMap刚初始化时实际没有分配存储空间,当table为空时containsKey方法将直接返回null。
三、结论
ConcurrentHashMap不能以null作为key,key为null时将返回NullPointerException;HashMap可用null作为key,key为null时,返回hash值为0指向位置的值。