1. 程式人生 > >關於map和null的一些小故事

關於map和null的一些小故事

最後,重點,為什麼同樣的key-value結構,hashmap就能putnull,啊?蛤?

找到了這樣的解答: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和Hashtable都是支援併發的,這樣會有一個問題,當你通過get(k)獲取對應的value時,如果獲取到的是null時,你無法判斷,它是put(k,v)的時候value為null,還是這個key從來沒有做過對映。HashMap是非併發的,可以通過contains(key)來做這個判斷。而支援併發的Map在呼叫m.contains(key)和m.get(key),m可能已經不同了。

個人覺得這個解答還是很有道理的,也是解決了心頭的一個疑惑,大牛們在設計時確實考慮的很多,在這裡分享給大家。

類似的解答還有這個: 
down vote 
I believe it is, at least in part, to allow you to combine containsKey and get into a single call. If the map can hold nulls, there is no way to tell if get is returning a null because there was no key for that value, or just because the value was null.

Why is that a problem? Because there is no safe way to do that yourself. Take the following code:

if (m.containsKey(k)) {
   return m.get(k);
} else {
   throw new KeyNotPresentException();
}
  • 1
  • 2
  • 3
  • 4
  • 5

Since m is a concurrent map, key k may be deleted between the containsKey and get calls, causing this snippet to return a null that was never in the table, rather than the desired KeyNotPresentException.

Normally you would solve that by synchronizing, but with a concurrent map that of course won’t work. Hence the signature for get had to change, and the only way to do that in a backwards-compatible way was to prevent the user inserting null values in the first place, and continue using that as a placeholder for “key not found”.