網(wǎng)站建設(shè)合同圖片網(wǎng)店推廣方案策劃書
Java putIfAbsent()
方法詳解
在 Java 中,putIfAbsent()
是 Map
接口中的一個(gè)方法,從 Java 8 開始引入。它用于向映射中添加一個(gè)鍵值對(duì),只有在該鍵尚未存在時(shí)才進(jìn)行添加操作。如果鍵已存在,則不會(huì)覆蓋原有值。
1. 方法定義
方法簽名
default V putIfAbsent(K key, V value)
參數(shù)
key
:要插入的鍵。value
:與鍵關(guān)聯(lián)的值。
返回值
- 如果鍵不存在,插入后返回
null
。 - 如果鍵已存在,則返回該鍵當(dāng)前的值,插入操作不會(huì)執(zhí)行。
2. 功能描述
-
檢查鍵是否存在:
- 如果鍵不存在,則將鍵值對(duì)插入到映射中。
- 如果鍵已存在,則保持原有鍵值對(duì)不變。
-
線程安全:
- 對(duì)于并發(fā)映射(如
ConcurrentHashMap
),putIfAbsent()
是線程安全的,保證了原子性。 - 對(duì)于普通
HashMap
,則不是線程安全的。
- 對(duì)于并發(fā)映射(如
-
避免覆蓋現(xiàn)有值:
- 與直接調(diào)用
put()
不同,putIfAbsent()
不會(huì)覆蓋現(xiàn)有的值。
- 與直接調(diào)用
3. 示例代碼
3.1 基本用法
import java.util.HashMap;
import java.util.Map;public class PutIfAbsentExample {public static void main(String[] args) {Map<String, String> map = new HashMap<>();// 初始插入map.put("A", "Apple");// 插入新鍵map.putIfAbsent("B", "Banana");System.out.println(map); // 輸出:{A=Apple, B=Banana}// 嘗試插入已存在的鍵map.putIfAbsent("A", "Avocado");System.out.println(map); // 輸出:{A=Apple, B=Banana}}
}
分析:
- 初次插入鍵
A
和B
。 - 對(duì)于鍵
A
,putIfAbsent()
不會(huì)覆蓋原值,因此保持不變。
3.2 結(jié)合返回值
import java.util.HashMap;
import java.util.Map;public class PutIfAbsentReturnExample {public static void main(String[] args) {Map<String, String> map = new HashMap<>();// 嘗試插入新鍵String result1 = map.putIfAbsent("C", "Cat");System.out.println(result1); // 輸出:null(鍵 "C" 不存在)// 再次嘗試插入相同鍵String result2 = map.putIfAbsent("C", "Carrot");System.out.println(result2); // 輸出:Cat(鍵 "C" 已存在,值保持為 "Cat")System.out.println(map); // 輸出:{C=Cat}}
}
3.3 使用 ConcurrentHashMap
putIfAbsent()
在 ConcurrentHashMap
中非常有用,可以實(shí)現(xiàn)線程安全的惰性初始化。
import java.util.concurrent.ConcurrentHashMap;public class ConcurrentPutIfAbsent {public static void main(String[] args) {ConcurrentHashMap<String, Integer> map = new ConcurrentHashMap<>();// 多線程同時(shí)嘗試插入map.putIfAbsent("key", 1);map.putIfAbsent("key", 2);System.out.println(map); // 輸出:{key=1}(只插入一次)}
}
4. putIfAbsent()
和 put()
的區(qū)別
特性 | put() | putIfAbsent() |
---|---|---|
覆蓋值 | 如果鍵已存在,則覆蓋舊值。 | 如果鍵已存在,則不覆蓋舊值。 |
返回值 | 返回舊值(如果存在),否則返回 null 。 | 如果鍵已存在,返回舊值,否則返回 null 。 |
性能 | 直接插入操作,可能覆蓋原值。 | 需要額外檢查鍵是否存在(線程安全時(shí)也加鎖)。 |
線程安全(ConcurrentMap) | 不是線程安全的,需要額外同步。 | 線程安全,尤其適用于 ConcurrentHashMap 。 |
5. 使用場(chǎng)景
5.1 避免覆蓋已存在值
當(dāng)希望保持某個(gè)鍵的初始值,避免被后續(xù)操作覆蓋時(shí):
map.putIfAbsent("key", "initialValue");
5.2 延遲初始化
在多線程環(huán)境中,putIfAbsent()
可以安全地初始化共享資源:
public static ConcurrentHashMap<String, String> cache = new ConcurrentHashMap<>();public static String getValue(String key) {return cache.putIfAbsent(key, "DefaultValue");
}
5.3 統(tǒng)計(jì)或計(jì)數(shù)
可以用 putIfAbsent()
初始化鍵的默認(rèn)值,用于統(tǒng)計(jì)場(chǎng)景:
map.putIfAbsent("count", 0);
map.put("count", map.get("count") + 1);
6. 注意事項(xiàng)
-
線程安全
- 對(duì)普通的
HashMap
使用putIfAbsent()
并不能實(shí)現(xiàn)線程安全。 - 如果需要線程安全,請(qǐng)使用
ConcurrentHashMap
或其他并發(fā)集合。
- 對(duì)普通的
-
返回值的使用
- 返回值可以用來(lái)判斷鍵是否已存在,從而決定后續(xù)操作。
-
性能開銷
- 對(duì)于并發(fā)集合(如
ConcurrentHashMap
),putIfAbsent()
內(nèi)部使用了鎖來(lái)保證原子性,可能有一定性能開銷。
- 對(duì)于并發(fā)集合(如
-
不可用于
null
值putIfAbsent()
不允許插入null
值,ConcurrentHashMap
會(huì)拋出NullPointerException
。
7. 總結(jié)
putIfAbsent()
是一種安全的插入操作:- 如果鍵不存在,則插入鍵值對(duì)。
- 如果鍵已存在,則保持原值不變。
- 線程安全性:
- 在
ConcurrentHashMap
中,putIfAbsent()
是線程安全的,可用于多線程環(huán)境。
- 在
- 適用場(chǎng)景:
- 避免值覆蓋。
- 延遲初始化或緩存加載。
- 實(shí)現(xiàn)統(tǒng)計(jì)或計(jì)數(shù)。
通過(guò)正確使用 putIfAbsent()
方法,可以簡(jiǎn)化代碼邏輯,同時(shí)確保數(shù)據(jù)的完整性和安全性,尤其在并發(fā)場(chǎng)景中非常實(shí)用。