例如,请参阅以下代码段:
Map<String,String> unsafemap=new HashMap<>();
unsafemap.put("hello",null);
unsafemap.put(null, null);
unsafemap.put("world","hello");
unsafemap.put("foo","hello");
unsafemap.put("bar","hello");
unsafemap.put("john","hello");
unsafemap.put("doe","hello");
System.out.println("changing null values");
for(Iterator<Map.Entry<String,String>> i=unsafemap.entrySet().iterator();i.hasNext();){
Map.Entry<String,String> e=i.next();
System.out.println("key : "+e.getKey()+" value :"+e.getValue());
if(e.getValue() == null){
//why is the below line not throwing ConcurrentModificationException
unsafemap.put(e.getKey(), "no data");
//same result, no ConcurrentModificationException thrown
e.setValue("no data");
}
//throws ConcurrentModificationException
unsafemap.put("testKey","testData");
}
System.out.println("---------------------------------");
for(Map.Entry<String,String> e :unsafemap.entrySet()){
System.out.println(e);
}
在迭代期间修改映射总是会导致异常,如果没有使用迭代器完成,例如iterator.remove()。因此,显然在迭代期间添加一个新值会抛出异常,但是如果修改了特定键/值对的值,为什么不抛出它?
答案 0 :(得分:0)
Entry
对象在您的第一种情况下已经存在,因此将使用e.value = value;
修改该值并返回,并且不会生成任何新条目。所以,这里也不例外。
在第二种情况下,对值对象所做的更改实际上不会影响地图,因此没有例外。
来自HashMap
源代码:
public V put(K key, V value) {
if (key == null)
return putForNullKey(value);
int hash = hash(key.hashCode());
int i = indexFor(hash, table.length);
for (Entry<K,V> e = table[i]; e != null; e = e.next) {
Object k;
if (e.hash == hash && ((k = e.key) == key || key.equals(k))) {
V oldValue = e.value;
e.value = value;
e.recordAccess(this);
return oldValue;
}
}
modCount++;
addEntry(hash, key, value, i);
return null;
}