国产亚洲精品福利在线无卡一,国产精久久一区二区三区,亚洲精品无码国模,精品久久久久久无码专区不卡

當(dāng)前位置: 首頁(yè) > news >正文

網(wǎng)站一般在哪建設(shè)網(wǎng)絡(luò)推廣人員

網(wǎng)站一般在哪建設(shè),網(wǎng)絡(luò)推廣人員,網(wǎng)站建設(shè)方案報(bào)價(jià)費(fèi)用明細(xì)價(jià)格,福州發(fā)布最新通報(bào)一、背景 最近設(shè)計(jì)某個(gè)類庫(kù)時(shí)使用了 ConcurrentHashMap 最后遇到了 value 為 null 時(shí)報(bào)了空指針異常的坑。 本文想探討下以下幾個(gè)問(wèn)題: (1) Map接口的常見子類的 kv 對(duì) null 的支持情況。 (2)為什么 ConcurrentHashM…

一、背景

最近設(shè)計(jì)某個(gè)類庫(kù)時(shí)使用了 ConcurrentHashMap 最后遇到了 value 為 null 時(shí)報(bào)了空指針異常的坑。
什么?.png
本文想探討下以下幾個(gè)問(wèn)題:
(1) Map接口的常見子類的 kv 對(duì) null 的支持情況。
(2)為什么 ConcurrentHashMap 不支持 key 和 value 為 null?
(3)如果 value 可能為 null ,該如何處理?
(4)有哪些線程安全的 Java Map 類?
(5) 常見的 Map 接口的子類,如 HashMap、TreeMapConcurrentHashMap 、ConcurrentSkipListMap 的使用場(chǎng)景。

二、探究

2.1 Map接口的常見子類的 kv 對(duì) null 的支持情況

下圖來(lái)源于孤盡老師 《碼出高效》 第 6 章 數(shù)據(jù)結(jié)構(gòu)與集合
Xnip2023-03-10_20-29-05.png

2.2 為什么 ConcurrentHashMap 不支持 key 和 value 為 null?

java.util.concurrent.ConcurrentHashMap#put 方法的注釋和源碼中可以非常容易得看出,不支持 key 和 value null。

    /*** Maps the specified key to the specified value in this table.* Neither the key nor the value can be null.** <p>The value can be retrieved by calling the {@code get} method* with a key that is equal to the original key.** @param key key with which the specified value is to be associated* @param value value to be associated with the specified key* @return the previous value associated with {@code key}, or*         {@code null} if there was no mapping for {@code key}* @throws NullPointerException if the specified key or value is null*/public V put(K key, V value) {return putVal(key, value, false);}/** Implementation for put and putIfAbsent */final V putVal(K key, V value, boolean onlyIfAbsent) {if (key == null || value == null) throw new NullPointerException();int hash = spread(key.hashCode());// 省略其他}

那么,為什么不支持 key 和 value 為 null 呢?
據(jù)查閱資料,ConcurrentHashMap 的作者 Doug Lea 自己的描述:

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.

可知 ConcurrentHashMap 是線程安全的容器,如果 ConcurrentHashMap 允許存放 null 值,那么當(dāng)一個(gè)線程調(diào)用 get(key) 方法時(shí),返回 null 可能有兩種情況:
(1) 一種是這個(gè) key 不存在于 map 中
(2) 另一種是這個(gè) key 存在于 map 中,但是它的值為 null。
這樣就會(huì)導(dǎo)致線程無(wú)法判斷這個(gè) null 是什么意思。
在非并發(fā)的場(chǎng)景下,可以通過(guò) map.contains(key)檢查是否包括該 key,從而斷定是不存在 key 還是存在key 但值為 null,但是在并發(fā)場(chǎng)景下,判斷后調(diào)用其他 api 之間 map 的數(shù)據(jù)已經(jīng)發(fā)生了變化,無(wú)法保證對(duì)同一個(gè) key 操作的一致性。

2.3 怎么解決?

2.3.1 封裝 put 方法,使用前判斷

建議封裝 put 方法,統(tǒng)一使用該方法對(duì) ConcurrentHashMap 的 put 操作進(jìn)行封裝,當(dāng) value 為 null 時(shí),直接 return 即可。

Map<String, Person> map = new ConcurrentHashMap<>();// 封裝 put 操作,為 null 時(shí)返回
private void putPerson(String key, Person value){if(value == null){return;}map.put(key, value);
}

2.3.2 使用 Optional 類型

使用 Optional

// 創(chuàng)建一個(gè) ConcurrentHashMap<String, Optional<String>>
Map<String, Optional<String>> map = new ConcurrentHashMap<>();// 插入或更新 key-value 對(duì)
map.computeIfAbsent("name", k -> Optional.ofNullable("Alice")); // 如果 name 不存在,則插入 ("name", Optional.of("Alice"))
map.computeIfAbsent("age", k -> Optional.ofNullable(null)); // 如果 age 不存在,則插入 ("age", Optional.empty())// 獲取 value
Optional<String> name = map.get("name"); // 返回 Optional.of("Alice")
Optional<String> age = map.get("age"); // 返回 Optional.empty()
Optional<String> gender = map.get("gender"); // 返回 null

2.3.3 自定義一個(gè)表示 null 的類

自定義表示 null 的類, 然后對(duì) put 和 get 操作進(jìn)行二次封裝,參考代碼如下:

// 定義一個(gè)表示 null 的類
public class NullValue extends Person{}// 創(chuàng)建一個(gè) ConcurrentHashMap<String, Object>
private Map<String, Person> map = new ConcurrentHashMap<>();private static final NullValue nullValue = new NullValue();//使用示例: 值不為 null 時(shí)
putPerson("1002", new Person("張三"));//使用示例: 值為 null 時(shí)
putPerson("1003", null);// 封裝設(shè)置操作
private void putPerson(String key,Person person){if(person == null){map.put(key, nullValue);return;}map.put(key, person);
}// 封裝獲取操作
private Person getPerson(String key){if(key == null){return;}Person person = map.get(key);if(person instanceof NullValue){return null;}return person;
}

2.3.4 使用其他線程安全的 Java Map 類

Java 中也有支持 key 和 value 為 null 的線程安全的集合類,比如 ConcurrentSkipListMap (JDK) 和 CopyOnWriteMap (三方)。

  • ConcurrentSkipListMap 是一個(gè)基于跳表的線程安全的 map,它使用鎖分段的技術(shù)來(lái)提高并發(fā)性能。它允許 key 和 value 為 null,但是它要求 key 必須實(shí)現(xiàn) Comparable 接口或者提供一個(gè) Comparator。
  • CopyOnWriteMap 是一個(gè)基于數(shù)組的線程安全的 map,它使用寫時(shí)復(fù)制的策略來(lái)保證并發(fā)訪問(wèn)的正確性。它允許 key 和 value 為 null。

注意 JDK 中沒有提供 CopyOnWriteMap,很多三方類庫(kù)提供了對(duì)應(yīng)的工具類。如org.apache.kafka.common.utils.CopyOnWriteMap

2.4 常見的 Map 接口的子類的使用場(chǎng)景

Map 接口有很多子類,那么他們各自的適用場(chǎng)景是怎樣的呢?
Xnip2023-03-10_20-30-43.png

使用場(chǎng)景主要取決于以下幾個(gè)方面:

  • 是否需要線程安全:如果需要在多線程環(huán)境下操作 Map,那么應(yīng)該使用 ConcurrentHashMap、ConcurrentSkipListMap,它們都是并發(fā)安全的。而 HashMap、TreeMap、HashTableLinkedHashMap則不是,并且 HashTable已經(jīng)被 ConcurrentHashMap取代。
  • 是否需要保證鍵的順序:如果需要按照鍵的自然順序或者插入順序遍歷 Map,那么應(yīng)該使用 TreeMap或者 LinkedHashMap,它們都是有序的。而 ConcurrentSkipListMap也是有序的,并且支持范圍查詢。其他類則是無(wú)序的。
  • 是否需要高效地訪問(wèn)和修改:如果需要快速地獲取和更新 Map中的元素,那么應(yīng)該使用 HashMap或者 ConcurrentHashMap,它們都是基于散列函數(shù)實(shí)現(xiàn)的,具有較高的性能。
    TreeMapConcurrentSkipListMap則是基于平衡樹實(shí)現(xiàn)的,具有較低的性能。CopyOnWriteMap 則是基于數(shù)組實(shí)現(xiàn)的,并發(fā)寫操作會(huì)復(fù)制整個(gè)數(shù)組,因此寫操作開銷很大。

在選擇合適的 Map 接口實(shí)現(xiàn)時(shí),需要根據(jù)具體需求和場(chǎng)景進(jìn)行權(quán)衡。

三、總結(jié)

基本功很重要,有時(shí)候基本功不扎實(shí),更容易遇到一些奇奇怪怪的坑。假設(shè)你不了解 ConcurrentHashMap 的 kv 不能為 null, 測(cè)試的時(shí)候沒有覆蓋這種場(chǎng)景,等上線以后遇到這個(gè)問(wèn)題可能直接導(dǎo)致線上問(wèn)題,甚至線上故障。

ConcurrentHashMap 作者在 put 方法注釋中給出了 kv 不允許為 null 的提示,并沒有在注釋中給出設(shè)計(jì)原因,給眾多讀者帶來(lái)了諸多困惑。這也給我們很大的啟發(fā),當(dāng)我們的某些設(shè)計(jì)容易引起別人的困惑和好奇時(shí),不僅要將注意事項(xiàng)放在注釋中,更應(yīng)該將設(shè)計(jì)原因放在注釋里,避免給使用者帶來(lái)困擾。

“適合自己的才是最好的”。正如不同的 Map 實(shí)現(xiàn)類各有千秋,使用場(chǎng)景各有不同,我們需要根據(jù)具體需求和場(chǎng)景進(jìn)行權(quán)衡一樣,我們?cè)谠O(shè)計(jì)方案時(shí)也會(huì)遇到類似的場(chǎng)景,我們能做的是根據(jù)場(chǎng)景選擇最適合的方案。

我們遇到的任何問(wèn)題,都是徹底掌握某個(gè)知識(shí)的絕佳機(jī)會(huì)。當(dāng)我們遇到問(wèn)題時(shí),應(yīng)該主動(dòng)掌握相關(guān)知識(shí),希望大家不僅能夠知其然,還要知其所以然。


創(chuàng)作不易,如果本文對(duì)你有幫助,歡迎點(diǎn)贊、收藏加關(guān)注,你的支持和鼓勵(lì),是我創(chuàng)作的最大動(dòng)力。
在這里插入圖片描述

http://m.aloenet.com.cn/news/31365.html

相關(guān)文章:

  • app界面設(shè)計(jì)流程圖河北搜索引擎優(yōu)化
  • 深圳做網(wǎng)站好的公司外貿(mào)推廣優(yōu)化公司
  • qq怎么做網(wǎng)站客服企業(yè)推廣策略
  • 對(duì)政府網(wǎng)站一體化服務(wù)建設(shè)的需求百度投放廣告一天多少錢
  • 烏魯木齊可以做網(wǎng)站的公司有哪些重慶網(wǎng)站seo教程
  • 網(wǎng)站開發(fā)語(yǔ)言是什么app開發(fā)多少錢
  • 西安企業(yè)網(wǎng)站建設(shè)哪家好怎么用手機(jī)創(chuàng)建網(wǎng)站
  • 什么網(wǎng)站ppt做的好免費(fèi)的seo優(yōu)化工具
  • 日語(yǔ)網(wǎng)站設(shè)計(jì)怎么做百度推廣平臺(tái)
  • 資陽(yáng)視頻網(wǎng)站建設(shè)廣州seo服務(wù)公司
  • 房地產(chǎn)網(wǎng)站解決方案女孩子做運(yùn)營(yíng)是不是壓力很大
  • 企業(yè)網(wǎng)站 asp php網(wǎng)絡(luò)優(yōu)化工具app手機(jī)版
  • 哪些專門做批發(fā)的網(wǎng)站有哪些短網(wǎng)址鏈接生成
  • 網(wǎng)站制作文案杭州長(zhǎng)治seo顧問(wèn)
  • seo發(fā)布網(wǎng)站某網(wǎng)站搜索引擎優(yōu)化
  • 網(wǎng)站開發(fā)包含上線嗎網(wǎng)絡(luò)營(yíng)銷的六大功能
  • wordpress網(wǎng)站例昆明網(wǎng)絡(luò)營(yíng)銷
  • 在國(guó)外做盜版電影網(wǎng)站嗎seo發(fā)帖工具
  • 做內(nèi)貿(mào)的網(wǎng)站武漢網(wǎng)站設(shè)計(jì)十年樂(lè)云seo
  • 做網(wǎng)站需要備案么長(zhǎng)沙seo培訓(xùn)班
  • 撫順市城市建設(shè)檔案館網(wǎng)站安卓?jī)?yōu)化大師新版
  • 做平臺(tái)網(wǎng)站外包多少錢啊常見的網(wǎng)絡(luò)營(yíng)銷方式有哪幾種
  • 京東網(wǎng)上購(gòu)物平臺(tái)如何快速優(yōu)化網(wǎng)站排名
  • 網(wǎng)站制作方案書博客網(wǎng)
  • 訂閱號(hào)欄目里做微網(wǎng)站網(wǎng)站排名靠前
  • 網(wǎng)絡(luò)營(yíng)銷專業(yè)建議百度seo優(yōu)化收費(fèi)標(biāo)準(zhǔn)
  • 兩學(xué)一做教育考試網(wǎng)站微信小程序怎么開通
  • WordPress微信密碼seo初級(jí)入門教程
  • 物聯(lián)網(wǎng)型網(wǎng)站開發(fā)企業(yè)網(wǎng)站建設(shè)服務(wù)
  • 做網(wǎng)站買域名網(wǎng)絡(luò)營(yíng)銷策劃方案3000字