转载

hashmap遍历时用map.remove方法为什么会报错?

笔者最近在调试项目bug的时候,遇到了一个很奇怪的bug,就是在对hashmap集合进行遍历的时候,同时做了remove操作,这个操作最后导致抛出了java.util.ConcurrentModificationException的错误。

带着疑惑,下面参考着源码,分析问题的原因。

首先,重现问题,构造一个map并往里面加元素:

private static HashMap<Integer, String> map = new HashMap<Integer, String>();;
	public static void main(String[] args) {
  	        for(int i = 0; i < 10; i++){  
	            map.put(i, "value" + i);  
	        }  
	}
复制代码

然后移除一些元素,此时就会报java.util.ConcurrentModificationException错误

for(Map.Entry<Integer, String> entry : map.entrySet()){  
         Integer key = entry.getKey();  
         if(key % 2 == 0){  
             System.out.println("To delete key " + key);  
             map.remove(key);  
             System.out.println("The key " + + key + " was deleted");  
         }  
复制代码
hashmap遍历时用map.remove方法为什么会报错?

分析问题

从报错中可以看出,HashMap$HashIterator.nextNode这个方法有代码错误了,点进去看,大概知道HashMap.this.modCount != this.expectedModCount 成立

hashmap遍历时用map.remove方法为什么会报错?

再看一下hashmap的remove操作是做了什么:

hashmap遍历时用map.remove方法为什么会报错?

这里对modCount进行了自增操作,表示操作动作+1。再看modCount和expectedModCount是什么东西

hashmap遍历时用map.remove方法为什么会报错?

问题原因

可以看出迭代器初始化的时候就对modCount和expectedModCount进行同步。

到此,可以看出报错的原因:

  • hashmap里维护了一个modCount变量,迭代器里维护了一个expectedModCount变量,一开始两者是一样的。
  • 每次进行hashmap.remove操作的时候就会对modCount+1,此时迭代器里的expectedModCount还是之前的值。
  • 在下一次对迭代器进行next()调用时,判断是否HashMap.this.modCount != this.expectedModCount,如果是则抛出异常。

解决问题

那什么情况下在遍历的时候可以删除map里面的元素呢?看下迭代器提供的remove方法:

hashmap遍历时用map.remove方法为什么会报错?

可以看出迭代器里remove了一个元素之后会对expectedModCount重新赋值,这样再次遍历的时候就不会报错了。所以之前的代码可以改成如下写法,直接调用迭代器的remove方法。

Iterator<Map.Entry<Integer, String>> it = map.entrySet().iterator();
      while(it.hasNext()){
          Map.Entry<Integer, String> entry = it.next();
          Integer key = entry.getKey();
          if(key % 2 == 0){
         	 System.out.println("To delete key " + key);
         	 it.remove();    
         	 System.out.println("The key " + + key + " was deleted");

          }
      }
复制代码
原文  https://juejin.im/post/5ca355dd6fb9a05e705c5515
正文到此结束
Loading...