為什么HashMap的鍵值可以為null,而ConcurrentHashMap不行?

寫在開頭

今天在寫《HashMap很美好,但線程不安全怎么辦?ConcurrentHashMap告訴你答案!》這篇文章的時候,漏了一個知識點,知道晚上吃飯的時候才凸顯想到,關于ConcurrentHashMap在存儲Key與Value的時候,是否可以存null的問題,按理說這是一個小問題,但build哥卻不敢忽視,尤其在現在很多面試官都極具挑剔的環境下,萬一同學們刷到了咱的博客,回答中遺漏了這個小細節,錯過了面試官的考驗,那咱可就成罪人了。
接下來我們就將HashMap、Hashtable、ConcurrentHashMap這三集合類的鍵值是否可以null的問題,放一起對比去學習一下。

Hashtable的鍵值與null

雖然我們在講解HashMap與Hashtable作對比時,已經說了Hashtable在存儲key與value時均不可為null,但當時的側重點全在HashMap身上,就沒有詳細的解釋原因,下面我們跟進put源碼中去一探緣由。

【源碼解析1】

public synchronized V put(K key, V value) {// 確認值不為空if (value == null) {throw new NullPointerException(); // 如果值為null,則拋出空指針異常}// 確認值之前不存在Hashtable里Entry<?,?> tab[] = table;int hash = key.hashCode(); // 如果key如果為null,調用這個方法會拋出空指針異常int index = (hash & 0x7FFFFFFF) % tab.length;//計算存儲位置//遍歷,看是否鍵或值對是否已經存在,如果已經存在返回舊值@SuppressWarnings("unchecked")Entry<K,V> entry = (Entry<K,V>)tab[index];for(; entry != null ; entry = entry.next) {if ((entry.hash == hash) && entry.key.equals(key)) {V old = entry.value;entry.value = value;return old;}}addEntry(hash, key, value, index);return null;}

通過Hashtable的put底層源碼,我們可以看到,方法體內,首先就對value值進行的判空操作,如果為空則拋出空指針異常;其次在計算hash值的時候,直接調用key的hashCode()方法,若keynull,自然也會報空指針異常,因此,我們在調用put方法存儲鍵值對時,key與value都非null。

HashMap的鍵值與null

我們同樣也通過HashMap的put方法去分析它的底層源碼,先上代碼。

【源碼解析2-hash()】

static final int hash(Object key) {int h;return (key == null) ? 0 : (h = key.hashCode()) ^ (h >>> 16);
}

在計算hash值的時候,hashmap中通過三目運算符做了空值處理,直接返回0,這樣最終計算出key應該存儲在數組的第一位上,且key是唯一性呢,因此,key最多存一個null;

【源碼解析3】

final V putVal(int hash, K key, V value, boolean onlyIfAbsent, boolean evict) {// 數組HashMap.Node<K,V>[] tab; // 元素HashMap.Node<K,V> p; // n 為數組的長度 i 為下標int n, i;// 數組為空的時候if ((tab = table) == null || (n = tab.length) == 0)// 第一次擴容后的數組長度n = (tab = resize()).length;// 計算節點的插入位置,如果該位置為空,則新建一個節點插入if ((p = tab[i = (n - 1) & hash]) == null)tab[i] = newNode(hash, key, value, null);///
}

回歸putVal()方法,我們逐句閱讀后也沒有發現對于value值為null的處理與限定,因此,它可以存儲為null的value值,我們知道HashMap的鍵值對特點如同身份證與人名一樣,key等同于身份證,全國唯一,而value值等同于人名,可以重復,比如全國有上萬個叫張偉的,所以value值也就同樣允許存儲多個null。

ConcurrentHashMap的鍵值與null

很多同學們可能會以為ConcurrentHashMap不過是HashMap在多線程環境下的版本,底層實現都一致,只是多了加鎖的操作,所以二者對于null的允許程度是一樣。
如果你是這樣想,那可就完全錯了,對于ConcurrentHashMap來說,它也不允許存儲鍵值對為null的數據。
Doug Lea(ConcurrentHashMap的設計者)曾這樣說道:

The main reason that nulls aren’t allowed in ConcurrentMaps (ConcurrentHashMaps, ConcurrentSkipListMaps) is that ambiguities that may be just barely tolerable in non-concurrent maps can’t be accommodated. The main one is that if map.get(key) returns null, you can’t detect whether the key explicitly maps to null vs the key isn’t mapped. In a non-concurrent map, you can check this via map.contains(key), but in a concurrent one, the map might have changed between calls.

大致的意思是,在單線程環境中,不會存在一個線程操作該 HashMap 時,其他的線程將該 HashMap 修改的情況,可以通過 contains(key)來做判斷是否存在這個鍵值對,從而做相應的處理;
而在多線程環境下,可能會存在多個線程同時修改鍵值對的情況,這時是無法通過contains(key)來判斷鍵值對是否存在的,這會帶來一個二義性的問題,Doug Lea說二義性是多線程中不能容忍的!

啥是二義性? 咱們通俗點講就是一個結果,2種釋義,就好比我們通過get方法獲取值的時候,返回一個null,其實我們是無法判斷是值本身為null還是說集合中就沒這個值!

所以說,ConcurrentHashMap的key和value均不可為null。

結尾彩蛋

如果本篇博客對您有一定的幫助,大家記得留言+點贊+收藏呀。原創不易,轉載請聯系Build哥!

在這里插入圖片描述
如果您想與Build哥的關系更近一步,還可以關注俺滴公眾號“JavaBuild888”,在這里除了看到《Java成長計劃》系列博文,還有提升工作效率的小筆記、讀書心得、大廠面經、人生感悟等等,歡迎您的加入!

在這里插入圖片描述

本文來自互聯網用戶投稿,該文觀點僅代表作者本人,不代表本站立場。本站僅提供信息存儲空間服務,不擁有所有權,不承擔相關法律責任。
如若轉載,請注明出處:http://www.pswp.cn/news/715415.shtml
繁體地址,請注明出處:http://hk.pswp.cn/news/715415.shtml
英文地址,請注明出處:http://en.pswp.cn/news/715415.shtml

如若內容造成侵權/違法違規/事實不符,請聯系多彩編程網進行投訴反饋email:809451989@qq.com,一經查實,立即刪除!

相關文章

【Java】面向對象之多態超級詳解!!

文章目錄 前言一、多態1.1 多態的概念1.2 多態的實現條件1.3 重寫1.3.1方法重寫的規則1.3.2重寫和重載的區別 1.4 向上轉型和向下轉型1.4.1向上轉型1.4.2向下轉型 1.5 多態的優缺點1.5.1 使用多態的好處1.5.2 使用多態的缺陷 結語 前言 為了深入了解JAVA的面向對象的特性&…

基于yolov5的電瓶車和自行車檢測系統,可進行圖像目標檢測,也可進行視屏和攝像檢測(pytorch框架)【python源碼+UI界面+功能源碼詳解】

功能演示&#xff1a; 基于yolov5的電瓶車和自行車檢測系統_嗶哩嗶哩_bilibili &#xff08;一&#xff09;簡介 基于yolov5的電瓶車和自行車檢測系統是在pytorch框架下實現的&#xff0c;這是一個完整的項目&#xff0c;包括代碼&#xff0c;數據集&#xff0c;訓練好的模型…

協程庫項目—日志模塊

日志模塊程序結構圖 sylarLog ├── LogLevel&#xff08;日志級別封裝類&#xff09; │ ├── 提供“從日志級別枚舉值轉換到字符串”、“從字符串轉換相應的日志級別枚舉值”等方法 ├── LogEvent&#xff08;日志事件類&#xff09; │ ├── 封裝日志事件的屬性…

Unity(第二十一部)動畫的基礎了解(感覺不了解其實也行)

1、動畫組件老的是Animations 動畫視頻Play Automatically 是否自動播放Animate Physics 驅動方式&#xff0c;勾選后是物理驅動Culling Type 剔除方式 默認總是動畫化就會一直執行下去&#xff0c;第二個是基于渲染播放&#xff08;離開鏡頭后不執行&#xff09;&#xff0c; …

高性能服務系列【二】CPU和內存

現代計算機的系統架構十分復雜。在服務器中&#xff0c;雙路處理器已經十分常見。最近Arm處理器實現雙路共384核心&#xff0c;要知道目前Linux內核最高只支持256核&#xff0c;這就有點尷尬。 多路處理器將越來越普遍&#xff0c;對性能的影響和傳統架構有不小的差別&#xf…

MySQL中json類型的字段

有些很復雜的信息&#xff0c;我們一般會用擴展字段傳一個json串&#xff0c;字段一般用text類型存在數據庫。mysql5.7以后支持json類型的字段&#xff0c;還可以進行sql查詢與修改json內的某個字段的能力。 1.json字段定義 ip_info json DEFAULT NULL COMMENT ip信息, 2.按…

GO基本類型一些記錄

基本類型一些記錄 1.直接粘貼文本進println(" ")2.中文字符串長度別用len( )3.byte本質是uint8 1.直接粘貼文本進println(" ") GoLand會自動補充轉義符 2.中文字符串長度別用len( ) 用相應編碼庫的方法&#xff0c;一般utf8即可 utf8.RuneCountInStrin…

PySide6實現word轉化pdf

目錄 一:實現思路 二:實現代碼 三:完整代碼和界面 一:實現思路 利用PySide6創建兩個按鈕和一個顯示區域,一個選擇文件按鈕,一個轉化按鈕和信息展示,操作文件按鈕選擇一個待轉化的word文檔。并且展示文件路徑到信息展示區,操作轉化按鈕,讀取選擇的文件轉化為pdf。并…

ThreadLocal介紹

文章目錄 ThreadLocal源碼分析&#xff1a;set方法get方法remove方法 ThreadLocal內存泄漏問題 ThreadLocal ThreadLocal提供了線程局部變量&#xff0c;每個線程都可以通過set和get方法來對這個變量進行操作&#xff0c;但不會和其他線程的局部變量沖突&#xff0c;實現了線程…

Doris實戰——拈花云科的數據中臺實踐

目錄 前言 一、業務背景 二、數據中臺1.0—Lambda 三、新架構的設計目標 四、數據中臺2.0—Apache Doris 4.1 新架構數據流轉 4.2 新架構收益 五、新架構的落地實踐 5.1 模型選擇 5.1.1 Unique模型 5.1.2 Aggregate模型 5.2 資源管理 5.3 批量建表 5.4 計算實現…

Stable Diffusion 模型分享:Realistic Stock Photo(真實的庫存照片)

本文收錄于《AI繪畫從入門到精通》專欄&#xff0c;專欄總目錄&#xff1a;點這里。 文章目錄 模型介紹生成案例案例一案例二案例三案例四案例五案例六案例七案例八 下載地址 模型介紹 條目內容類型大模型基礎模型SDXL 1.0來源CIVITAI作者PromptSharingSamaritan文件名稱reali…

原生GO開發的博客系統

Go博客實戰教程&#xff0c;是一個練手級項目教程&#xff0c;使用原生Go開發&#xff0c;未使用任何框架。 如何使用原生Go開發一個web項目 循序漸進&#xff0c;掌握編程思維和思路 初步具有工程思維&#xff0c;能適應一般的開發工作 1. 搭建項目 package mainimport (&q…

Vue3_2024_1天【Vue3創建和響應式,對比Vue2】

前言&#xff1a; Vue3對比Vue2版本&#xff0c;它在性能、功能、易用性和可維護性方面都有顯著的提升和改進。 性能優化&#xff1a;模板編譯器的優化、對Proxy的支持以及使用了更加高效的Virtual DOM算法等。這使得Vue3的打包大小減少了41%&#xff0c;初次渲染提速55%&#…

【MATLAB源碼-第153期】基于matlab的OFDM系統插入導頻和訓練符號兩種信道估計方式誤碼率對比仿真。

操作環境&#xff1a; MATLAB 2022a 1、算法描述 OFDM&#xff08;Orthogonal Frequency Division Multiplexing&#xff0c;正交頻分復用&#xff09;是一種高效的無線信號傳輸技術&#xff0c;廣泛應用于現代通信系統&#xff0c;如Wi-Fi、LTE和5G。OFDM通過將寬帶信道劃分…

使用docker方式測試部署django項目(客戶催)

需求 1&#xff1a;已有django項目–weidanyewu 2&#xff1a;希望在服務器上測試部署–客戶催 3&#xff1a;沒完善django的啟動 4&#xff1a;使用臨時數據庫進行演示 5&#xff1a;使用python3.10版本鏡像 6&#xff1a;展示端口80 7&#xff1a;后臺執行django程序 8&#…

【C語言】熟悉文件順序讀寫函數

前言 本篇詳細介紹了 文件順序讀寫常用函數&#xff0c;快來看看吧~ 歡迎關注個人主頁&#xff1a;逸狼 創造不易&#xff0c;可以點點贊嗎~ 如有錯誤&#xff0c;歡迎指出~ 目錄 前言 ?編輯 文件順序讀寫函數 fgetc函數 示例 fputc函數 逐個字符寫入 寫入26個字母 文…

手寫模擬器,解放雙手!效果炸裂的生產工具

手寫模擬器是一款基于Handright的仿手寫圖片生成軟件&#xff0c;可以讓你的電腦和手機也能寫出漂亮的手寫字&#xff0c;你只需要輸入你想要寫的內容&#xff0c;選擇你喜歡的字體和背景&#xff0c;就可以生成一張高仿真的手寫圖片&#xff0c;用于各種場合&#xff0c;比如做…

uniapp中canvas的基礎使用

canvas簡介 canvas是uniapp中提供的一個組件,用于生成自定義的圖形界面。通過canvas,我們可以通過JavaScript代碼在頁面上繪制各種圖形和圖像。 使用canvas 在頁面中添加canvas 首先需要在頁面的template中添加一個canvas組件: <template><view><canvas ca…

linux:iostat 用法詳解

文章目錄 描述語法參數例子 描述 iostat 是一個在類Unix操作系統中常用的系統監控工具&#xff0c;尤其是Linux系統中&#xff0c;它主要用于收集和報告中央處理器(CPU)使用情況以及磁盤輸入/輸出(I/O)統計數據。以下是 iostat 命令的基本用法及其參數詳解&#xff1a; 語法 …

代碼隨想錄三刷 day11 | 棧與隊列之 20. 有效的括號 1047. 刪除字符串中的所有相鄰重復項 150. 逆波蘭表達式求值

三刷day11 20. 有效的括號1047. 刪除字符串中的所有相鄰重復項150. 逆波蘭表達式求值 20. 有效的括號 題目鏈接 解題思路&#xff1a; 有三種不匹配的情況&#xff1a; 第一種情況&#xff0c;字符串里左方向的括號多余了 。 第二種情況&#xff0c;括號沒有多余&#xff0c;…