代碼如下
/** * 測試ConcurrentHashMap null鍵和null值的問題 * @return */ @RequestMapping(value = "/get_nacos") public String getNacos(){ ConcurrentHashMap<String,String> map =new ConcurrentHashMap<>(1); map.put("testKey", null); String nullValue = map.get("sss"); return nullValue; } }
其中在執行put操作時,會報錯,信息如下:
java.lang.NullPointerException: null at java.util.concurrent.ConcurrentHashMap.putVal(ConcurrentHashMap.java:1011) ~[na:1.8.0_162] at java.util.concurrent.ConcurrentHashMap.put(ConcurrentHashMap.java:1006) ~[na:1.8.0_162] at com.gabriel.stage.controller.TestController.getNacos(TestController.java:44) ~[classes/:na] at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method) ~[na:1.8.0_162] at sun.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:62) ~[na:1.8.0_162] at sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43) ~[na:1.8.0_162] at java.lang.reflect.Method.invoke(Method.java:498) ~[na:1.8.0_162] at org.springframework.util.ReflectionUtils.invokeMethod(ReflectionUtils.java:282) ~[spring-core-5.1.7.RELEASE.jar:5.1.7.RELEASE]
那么這里就有一個疑問了,為什么HashMap能存null鍵和null值,ConcurrentHashMap就不能存null鍵和null值了呢,並且還會出現空指針異常
個人理解如下:
ConrrentHashMap 是一個用於多線程並發場景下的並發容器(Map),也就是在多線程環境下執行增刪改查方法要保證線程安全性,
例如containsKey()方法中
public boolean containsKey(Object key) { return get(key) != null; }
該方法會調用get方法去查詢key值是否存在,此時如果key值是我們手動存進去的,這個時候就會在代碼語義上有區別,無法區分是真的沒有該key 還是我們存儲的key,
並且在調用get()方法時,可能會出現別的線程修改為null鍵和null值的情況,這中情況在並發場景下會產生歧義;
HashMap本身是一個線程不安全的容器(Map),也就是使用場景局限於單線程環境,因此存儲null鍵null值 通常不會有什么問題,
HashMap將存儲的null鍵存儲到數組的第1個元素;