java在遍历map的时候对元素进行移除出现的问题分析

本文深入探讨了在Java中使用HashMap时,为何在迭代过程中移除元素会引发ConcurrentModificationException异常。通过分析源码,解释了modCount与expectedModCount的作用及差异,提出了正确的元素移除方式。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

在日常的开发中,我们经常需要对map,list等容器进行移除,但是处理不小心就会抛出ConcurrentModificationException异常,这到底是什么原因造成的以及如何避免?这个本博文分析的重点。

首先看一下这个map的遍历程序

package test1;

import java.util.HashMap;
import java.util.Map;

public class test {
    public static void main(String[] args){
        Map<Integer,Integer> map=new HashMap<>();
        //初始化map
        for(int i=0;i<10;i++){
            map.put(i,i);
        }
        for(Map.Entry<Integer,Integer> entry:map.entrySet()){
            if(entry.getKey()==1){
                map.remove(entry.getKey());
            }
            System.out.println(entry.getKey()+" "+entry.getValue());
        }
    }
}

运行的时候会抛出ConcurrentModificationException:

这是什么原因造成的呐?下面我们来分析一下源码

首先HashMap里面有个成员属性,如下图

这个成员属性是记录map一共被修改的次数的,也就是对map进行put,remove的时候,这个modCount也是需要增加次数的。

而当我们使用迭代器Iterator对map进行遍历的时候,在迭代器创建的时候就将这个值赋予给了迭代器里面的一个成员变量expectedModCount。

然后我们再来看看map.remove()方法发生了什么?

问题就出在这里,map.remove()方法只会修改modCount成员变量,执行一次remove()方法后modCount变量加1,而expectedModCount还是原来的值。

因此在下一次迭代器执行next()方法的时候 ,就会因为modeCount和expectedModCount这两个不一致而抛出错误。

所以总结一下,凡是用迭代器遍历并用map.remove()移除的都会出现这个问题。

那么,日常开发中,我们想在迭代中移除元素,那该怎么办呢?解决办法很简单,代码修改如下:

package test1;

import java.util.HashMap;
import java.util.Iterator;
import java.util.Map;

public class test {
    public static void main(String[] args){
        Map<Integer,Integer> map=new HashMap<>();
        //初始化map
        for(int i=0;i<10;i++){
            map.put(i,i);
        }
        Iterator<Map.Entry<Integer,Integer>> iterator=map.entrySet().iterator();
        while (iterator.hasNext()){
            Map.Entry<Integer, Integer> next=iterator.next();
            int key=next.getKey();
            int value=next.getValue();
            if(key==1){
                iterator.remove();
            }
            System.out.println(key+" "+value);
        }
    }
}

只要用迭代器中的remove()方法删除元素就行了,那我们再来看看迭代器中的remove()方法做了什么。

 可以看到每一次remove,都会expectedModCount同步一下modCount,这就不会造成两者数值不相等啦。

重点来了,那为什么java要这样设计呢?是不是大牛们吃饱了撑着了呢?想什么呐,肯定不是噶

 原因如下:HashMap和keySet的remove方法都可以通过传递key参数删除任意的元素,而iterator只能删除当前元素(current),一

旦删除的元素是iterator对象中next所正在引用的,如果没有通过modCount、 expectedModCount的比较实现快速失败抛出异

常,下次循环该元素将成为current指向,此时iterator就遍历了一个已移除的过期数据。

评论 2
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值