在使用hashMap的过程中遇到的一个问题,记录一下。
之前在做一个功能的时候,需要删除hashMap中的一些元素,当时最先想到的方案就是直接for循环,然后在循环中调用remove方法删除元素,如下所示;
HashMap<String,String> map = new HashMap();
map.put("11","1");
map.put("22","2");
for (String key : map.keySet()) {
if ("11".equals(key))
map.remove(key);
}
运行代码后就抛出如下异常:
后来在网上查了一些资料,并查看了一些源码。
原因是每次我们对hashmap进行修改操作时都会由一个modCount变量记录修改次数;
hashmap调用for循环的时候底层还是创建了一个迭代器
迭代器创建时会将 expectedModCount = modCount;
在上面报错代码中,我对hashmap进行了一次remove操作,modCount的值就会加1,比如说我们上面进行了两次put操作,modCount的值为2,再执行remove之后,modCount的值为3,但是在创建迭代器时,modCount将值赋给了expectedModCount,此时expectedModCount的值为2;
当下次循环时迭代器会去调用它的next()方法
next()方法中调用了nextNode()方法
此时会去校验modCount和expectedModCount的值是否相等,如果不相等就会抛出ConcurrentModificationException()异常。
解决方案:
要解决这个问题可以调用iterator迭代器的remove()方法。
HashMap<String,String> map = new HashMap();
map.put("11","1");
map.put("22","2");
// for (String key : map.keySet()) {
// if ("11".equals(key))
// map.remove(key);
// }
Iterator<String> iterator = map.keySet().iterator();
while (iterator.hasNext()) {
String next = iterator.next();
if ("11".equals(next)){
iterator.remove();
}
此时代码可以正常运行。
我们来看一下iterator的remove()方法;
在执行完删除操作后会再次将modCount的值赋值给expectedModCount。
以下是我的一些猜想:
因为hashmap是一个线程不安全的集合,为了防止在并发情况下,一个线程在循环时,另一个线程对hashMap集合进行修改操作而设计的。(fast-fail 快速失败的机制)。
所以这个异常叫ConcurrentModificationException()并发修改异常;
但是在单线程情况下,一些不恰当的操作也会触发这个异常。