美團(tuán)太細(xì)了,HashMap可以存Null,ConcurrentHashMap不可以,為什么?
我們知道,ConcurrentHashMap在使用時(shí),和HashMap有一個(gè)比較大的區(qū)別,那就是HashMap中,null可以作為鍵或者值都可以。而在ConcurrentHashMap中,key和value都不允許為null。
那么,為什么呢?為啥ConcurrentHashMap要設(shè)計(jì)成這樣的呢?
關(guān)于這個(gè)問(wèn)題,其實(shí)最有發(fā)言權(quán)的就是ConcurrentHashMap的作者——Doug Lea。
他自己曾經(jīng)出面解釋過(guò)這個(gè)問(wèn)題,內(nèi)容如下(原文地址已經(jīng)打不開(kāi)了,大家將就著看一下截圖吧) :
主要意思就是說(shuō):
ConcurrentMap(如ConcurrentHashMap、ConcurrentSkipListMap)不允許使用null值的主要原因是,在非并發(fā)的Map中(如HashMap),是可以容忍模糊性(二義性)的,而在并發(fā)Map中是無(wú)法容忍的。
假如說(shuō),所有的Map都支持null的話,那么map.get(key)就可以返回null,但是,這時(shí)候就會(huì)存在一個(gè)不確定性,當(dāng)你拿到null的時(shí)候,你是不知道他是因?yàn)楸緛?lái)就存了一個(gè)null進(jìn)去還是說(shuō)就是因?yàn)闆](méi)找到而返回了null。
在HashMap中,因?yàn)樗脑O(shè)計(jì)就是給單線程用的,所以當(dāng)我們map.get(key)返回null的時(shí)候,我們是可以通過(guò)map.contains(key)檢查來(lái)進(jìn)行檢測(cè)的,如果它返回true,則認(rèn)為是存了一個(gè)null,否則就是因?yàn)闆](méi)找到而返回了null。
但是,像ConcurrentHashMap,它是為并發(fā)而生的,它是要用在并發(fā)場(chǎng)景中的,當(dāng)我們map.get(key)返回null的時(shí)候,是沒(méi)辦法通過(guò)通過(guò)map.contains(key)檢查來(lái)準(zhǔn)確的檢測(cè),因?yàn)樵跈z測(cè)過(guò)程中可能會(huì)被其他線程鎖修改,而導(dǎo)致檢測(cè)結(jié)果并不可靠。
所以,為了讓ConcurrentHashMap的語(yǔ)義更加準(zhǔn)確,不存在二義性的問(wèn)題,他就不支持null。