為什么ConcurrentHashMap的key value不能為null,map可以?
源碼
if (key == null || value == null) throw new NullPointerException();
二義性
假定ConcurrentHashMap也可以存放value為null的值。那不管是HashMap還是ConcurrentHashMap調(diào)用map.get(key)的時(shí)候,如果返回了null,那么這個(gè)null,
都有兩重含義:
1.這個(gè)key從來沒有在map中映射過。
2.這個(gè)key的value在設(shè)置的時(shí)候,就是null。
為什么map允許value=null
對于HashMap的正確使用場景是在單線程下使用。
在單線程中,當(dāng)我們得到的value是null的時(shí)候,我可以用hashMap.containsKey(key)方法來區(qū)分上面說的兩重含義。
所以當(dāng)map.get(key)返回的值是null,在HashMap中雖然存在二義性,但是結(jié)合containsKey方法可以避免二義性。
為什么ConcurrentHashMap不允許
ConcurrentHashMap的使用場景為多線程。
用反證法來推理,假設(shè)concurrentHashMap允許存放值為null的value。
這時(shí)有A、B兩個(gè)線程。
線程A調(diào)用concurrentHashMap.get(key)方法,返回為null,我們還是不知道這個(gè)null是沒有映射的null還是存的值就是null。
我們假設(shè)此時(shí)返回為null的真實(shí)情況就是因?yàn)檫@個(gè)key沒有在map里面映射過。那么我們可以用concurrentHashMap.containsKey(key)來驗(yàn)證我們的假設(shè)是否成立,我們期望的結(jié)果是返回false。
但是在我們調(diào)用concurrentHashMap.get(key)方法之后,containsKey方法之前,有一個(gè)線程B執(zhí)行了concurrentHashMap.put(key,null)的操作。那么我們調(diào)用containsKey方法返回的就是true了。這就與我們的假設(shè)的真實(shí)情況不符合了。也就是上面說的二義性。
對于key不能為null
源碼就是這樣。。
補(bǔ)充:Hashtable/HashMap與key/value為null的關(guān)系
1、 HashMap計(jì)算key的hash值時(shí)調(diào)用單獨(dú)的方法,在該方法中會(huì)判斷key是否為null,如果是則返回0;而Hashtable中則直接調(diào)用key的hashCode()方法,因此如果key為null,則拋出空指針異常。
2、 HashMap將鍵值對添加進(jìn)數(shù)組時(shí),不會(huì)主動(dòng)判斷value是否為null;而Hashtable則首先判斷value是否為null。
3、以上原因主要是由于Hashtable繼承自Dictionary,而HashMap繼承自AbstractMap。
4、雖然ConcurrentHashMap也繼承自AbstractMap,但是其也過濾掉了key或value為null的鍵值對。
以上為個(gè)人經(jīng)驗(yàn),希望能給大家一個(gè)參考,也希望大家多多支持腳本之家。如有錯(cuò)誤或未考慮完全的地方,望不吝賜教。
相關(guān)文章
SpringBoot整合Dubbo框架,實(shí)現(xiàn)RPC服務(wù)遠(yuǎn)程調(diào)用
Dubbo是一款高性能、輕量級的開源Java RPC框架,它提供了三大核心能力:面向接口的遠(yuǎn)程方法調(diào)用,智能容錯(cuò)和負(fù)載均衡,以及服務(wù)自動(dòng)注冊和發(fā)現(xiàn)。今天就來看下SpringBoot整合Dubbo框架的步驟2021-06-06Java日常練習(xí)題,每天進(jìn)步一點(diǎn)點(diǎn)(9)
下面小編就為大家?guī)硪黄狫ava基礎(chǔ)的幾道練習(xí)題(分享)。小編覺得挺不錯(cuò)的,現(xiàn)在就分享給大家,也給大家做個(gè)參考。一起跟隨小編過來看看吧,希望可以幫到你2021-07-07Spring?boot集成easy?excel實(shí)現(xiàn)導(dǎo)入導(dǎo)出功能
這篇文章主要介紹了Spring?boot集成easy?excel實(shí)現(xiàn)導(dǎo)入導(dǎo)出操作,使用easyexcel,首先要引入easyexcel的maven依賴,具體的版本根據(jù)你的需求去設(shè)置,本文結(jié)合實(shí)例代碼講解的非常詳細(xì),需要的朋友可以參考下2024-05-05詳解使用spring aop實(shí)現(xiàn)業(yè)務(wù)層mysql 讀寫分離
本篇文章主要介紹了使用spring aop實(shí)現(xiàn)業(yè)務(wù)層mysql 讀寫分離,小編覺得挺不錯(cuò)的,現(xiàn)在分享給大家,也給大家做個(gè)參考。一起跟隨小編過來看看吧2017-01-01Java concurrency集合之LinkedBlockingDeque_動(dòng)力節(jié)點(diǎn)Java學(xué)院整理
LinkedBlockingDeque是雙向鏈表實(shí)現(xiàn)的雙向并發(fā)阻塞隊(duì)列。該阻塞隊(duì)列同時(shí)支持FIFO和FILO兩種操作方式,即可以從隊(duì)列的頭和尾同時(shí)操作(插入/刪除);并且,該阻塞隊(duì)列是支持線程安全。2017-06-06