List 的 ForEach 可能导致 ConcurrentModificationException?

微带功分器设计与ADS-EM联合仿真实战解析 本文详细解析了微带功分器设计与ADS-EM联合仿真的实战技巧,涵盖特性阻抗计算、ADS原理图设计、版图生成与EM仿真等关键步骤。通过实际案例分享,帮助工程师掌握射频电路设计中的核心技术和调试方法,提升功分器设计效率与性能。 阅读详情
问题:

ConcurrentModificationException 问题多出现在 List 的 forEach 或者 Iterator 循环中,调用 List 中的方法操作数据。
例如:

//List Iterator 循环里操作数据
public static void main(String[] args) {
    ArrayList<int> list=new ArrayList<String>();
    list.add("a");
    list.add("b");
    list.add("c");
    
    Iterator<String> iterator=list.iterator();
    while(iterator.hasNext()){
        String str = iterator.next();
        if(str.equals("a"){
            list.remove("a");
        }
    }
    System.out.println(list);
}

//List forEach 循环里操作数据
public static void main(String[] args) {
    ArrayList<int> list=new ArrayList<String>();
    list.add("a");
    list.add("b");
    list.add("c");
    
    for(String str : list){
        if(str.equals("a"){
            list.remove("a");
        }
    }
    System.out.println(list);
}

上面两种情况都会导致 ConcurrentModificationException,那么这是为什么呢?

原因:

在分析之前先了解一点,其实 List 的 forEach 就是 Iterator,是 List 创建了一个内部类 Itr 去实现 Iterator 接口,所以下面不会区分这两种情况,以 ArrayList forEach 进行分析。

知道了 forEach 其实就是通过 Itr 来实现的循环的,那么咱们来看看这个类。

private class Itr implements Iterator<E> {
    protected int limit = ArrayList.this.size;
    // 第一个元素的游标
    int cursor;
    // 上一个元素的游标
    int lastRet = -1; 
    // expectedModCount:Itr 维护的一个 List 修改记录
    // modCount:List 维护的一个 List 修改记录
    int expectedModCount = modCount;

    public boolean hasNext() {
        return cursor < limit;
    }

    @SuppressWarnings("unchecked")
    public E next() {
        if (modCount != expectedModCount)
            throw new ConcurrentModificationException();
        int i = cursor;
        if (i >= limit)
            throw new NoSuchElementException();
        Object[] elementData = ArrayList.this.elementData;
        if (i >= elementData.length)
            throw new ConcurrentModificationException();
        cursor = i + 1;
        return (E) elementData[lastRet = i];
    }
    .... 其余代码省略 ....
}

  前面说到过 forEach 就是 Iterator 实现的,这里的 hasNext() 方法是用来判断是否还有数据需要遍历,而关键的就在 next() 方法中。这个方法是用来获取下一个元素的,但在获取之前做了一个判断,就是 Itr 维护的修改记录(expectedModCount)要和 List 维护的修改记录(modCount)相等才能继续,不然说明数据源已经被修改了,这时获取到的下一个元素已经不准确了。
  再来看怎样会导致两个类维护的变量不一致。(以 remove() 方法为例)

public boolean remove(Object o) {
    if (o == null) {
        for (int index = 0; index < size; index++)
            if (elementData[index] == null) {
                fastRemove(index);
                return true;
            }
    } else {
        for (int index = 0; index < size; index++)
            if (o.equals(elementData[index])) {
                fastRemove(index);
                return true;
            }
    }
    return false;
}

private void fastRemove(int index) {
    modCount++;
    int numMoved = size - index - 1;
    if (numMoved > 0){
        System.arraycopy(elementData, index+1, elementData, index,numMoved);
    }
    elementData[--size] = null; // clear to let GC do its work
}

 上面代码可以看出 remove() 方法调用 fastRemove() 方法,实现删除数据,并且将 List 维护的修改记录(modCount)+1,但是此时 Itr 中维护的修改记录(expectedModCount) 并没有改变。

  将上面两部分总结一下就是:List 的 forEach 循环就是利用 List 内部类 Itr 实现的。Itr 中维护了一个 List 修改记录变量 expectedModCount,List 中也维护了一个修改记录变量 modCount。如果你在 forEach 或者 Iterator 循环中调用 List 类的操作数据方法,此时只是修改的 modCount,在循环取下一个元素时(即调用 Itr 的 next() 方法),由于 expectedModCount 与 modCount 已经不相等,导致抛出 ConcurrentModificationException,来告诉你 List 已经被修改了,此时获取 List 中的元素已经是不准确的了。

解决方法:
  1. 使用 Itr 中的方法操作数据
  2. 不使用 Iterator 或者 forEach 循环,使用 for 循环自己维护索引
  3. 使用并发包提供的集合类存储与处理数据,例如 CopyOnArrayList 等
手把手教你用Wireshark抓包分析Profinet非周期通信(附实战案例) 本文详细解析了PROFINET非周期通信(RTA)的技术原理与实战应用,通过Wireshark抓包分析,揭示从PLC请求到驱动器响应的完整对话过程。涵盖实验环境搭建、关键配置步骤、典型参数访问流程及故障诊断案例,帮助工程师深入理解并优化工业网络通信性能。 阅读详情

相关推荐

高精度SAR ADC设计实战:从建模到版图的16位1MSPS实现

本文详细介绍了16位1MSPS高精度SAR ADC的设计过程,从建模到版图实现的完整流程。重点探讨了分段电容阵列设计、校准算法实现及版图匹配等关键技术,展示了如何在180nm工艺下实现92.5dB SNDR和109.6dB SFDR的高性能指标。文章特别强调了整数桥接电容设计对提升匹配精度的关键作用,为高精度模数转换器设计提供了实用参考。

weixin_33724046的博客 436

SpringBoot造成事务失效的几种情况

@Transactional 注解的方法不是 public 方法 方法抛出的异常类型不是 RuntimeException 方法抛出异常时,使用try.catch.进行了捕获,而 catch 语句块没有 throw new RuntimeExecption 异常 @Transactional注解所在的类没有纳入 Spring 容器管理 MySQL 存储引擎采用是是 MyISAM 而非 InnoDB ...

分享一些工作和生活中的一些心得,主要分享一些Java和JavaScript方面的知识,也会包括服务器运维等其他知识 1748

从防御者视角复盘:用WinArpAttacker和Wireshark在Windows上模拟并检测ARP欺骗攻击

本文详细解析了Windows平台下的ARP欺骗攻击与防御策略,通过WinArpAttacker和Wireshark工具模拟攻击并检测异常流量。文章涵盖实验环境搭建、攻击原理深度解析、流量特征分析及企业级防御方案,帮助安全运维人员全面掌握ARP攻击检测与防护技术。

weixin_30918633的博客 120

Java中的迭代器和foreach原理&foreach循环报NullPointerException空指针异常

最近写了个接口,一直报Exception in thread “main” java.lang.NullPointerException,定位到报错的语句,发现是一个foreach语句报错:于是打个断点查看,发现 userInfoBaseBOList = null,难怪一直报空指针。

qq_43842093的博客 2601

C# OpenCvSharp4实战:5分钟搞定工业视觉模板匹配(附完整代码)

本文为C#开发者提供了基于OpenCvSharp4的工业视觉模板匹配实战指南。通过详细的环境搭建、核心原理解析和完整代码示例,重点介绍了如何使用`matchTemplate`函数,特别是`CCoeffNormed`方法,快速实现高精度、抗光照变化的模板匹配,并分享了多目标匹配、图像预处理等工业级优化技巧。

weixin_29053067的博客 500

描边盛开火玫瑰

python描边盛开火玫瑰 代码如下 import turtle as t t.setup(800,800) t.hideturtle() t.speed(11) t.penup() t.goto(50,-450) t.pensize(5) t.pencolor("black") t.seth(140) t.pendown() t.speed(10) t.circle(-300,60) t.fd(100) #jiaodu80 #1ye t.seth(10) t.fd(50) t.fillcolor("gr

weixin_50973371的博客 2062

带事务性的list.parallelStream().forEach()单条或多条数据操作,动态数据源会失效

未完待续。。。。。。。

Nick&Freya'Blog 839

详解APM的开方控制器sqrt_controller

前言 前面说过,sqrt_controller是对P项进行整定用途的,目的就是让P项的控制响应“软”下来,实际上就是一个经过改进的P控制器。读懂了sqrt_controller,那么你对APM的P控制器就了解得差不多了。 仅讨论P控制器,sqrt_controller的作用就是设定一个量linear_dist,以这个量的正负值为分界线划分出一个线性区域范围,在这个范围内表示误差量还很小,遵循Kp*error计算方式输出控制量。 超过linear_dist后,表明误差较大,此时不能由着误差单纯按照线性方式乘以

moumde的博客 4893

Java foreach ConcurrentModificationException解读

这里foreach指的是 for (int num: nums)这种用法 下面的代码 //BFS List<Node> current = new ArrayList<>(); List<Node> next = new ArrayList<>(); while (!current.isEmpty()) { for (Node node : ...

蓝羽飞鸟的博客 497

3步!Spring Boot+OCR引擎秒提身份证/营业执照?手把手教你从零实现!

OCR技术革新文档识别效率 本文演示了如何利用Spring Boot+Tesseract OCR+OpenCV构建自动化文档识别系统。相比传统人工录入,OCR技术可实现: 5秒极速提取身份证/营业执照关键信息 精准识别中文文本(准确率90%+) 正则过滤自动匹配结构化数据 技术要点: OpenCV图像预处理(灰度化+二值化) Tesseract多语言OCR识别 正则表达式精准提取证件号码 效率提升达100倍,错误率降低90%,适用于金融、政务等需要批量处理证件的场景。

java专栏 903

多智能体记忆架构设计:从分层模型到一致性实践

多智能体记忆架构本质上是一个有状态、分布式、支持遗忘的知识系统。从分层模型入手,结合RBAC隔离、版本向量一致性以及混合存储,可以构建出既灵活又健壮的生产级方案。可微分记忆:让记忆的读写操作嵌入端到端训练。基于大模型的记忆压缩:用LLM自动生成情景摘要,取代规则式遗忘。联邦记忆:不同组织之间的多智能体系统在不共享原始数据的情况下协同记忆。希望本文能为你的多智能体项目提供一块坚实的基石。欢迎在评论区分享你在实践中遇到的记忆架构难题。

Ven%的博客 169

foreach中remove/add,抛出ConcurrentModificationException异常

 一、foreach中remove,抛异常 public static void main(String[] args) { List&lt;String&gt; list = new ArrayList&lt;&gt;(); list.add("1"); list.add("2"); list.add("3"); list.add("4"); for (String

stonesdd的专栏 413

Data-Structures-and-Algorithm-Analysis-in-Java.pdf

作者: Weiss, Mark A. 出版社: Addison Wesley Data Structures and Algorithm Analysis in Java is an “advanced algorithms” book that fits between traditional CS2 and Algorithms Analysis courses. In the old ACM Curriculum Guidelines, this course was known as CS7. This text is for readers who want to learn good programming and algorithm analysis skills simultaneously so that they can develop such programs with the maximum amo...

java foreach iterator remove_不要在 foreach 循环里进行元素的 remove/add 操作。remove 元素请使用 Iterator 方式,如果并发操作,需要对 ...

下图是来自阿里巴巴java开发手册,里面的例子有些特殊,在后面会有一般的例子,请往后看。个人理解:在foreach循环里面进行元素的remove/add操作就是:在foreach循环里使用集合本身的remove/add方法, Iterator方式就是使用集合对应的iterator的remove/add方法,即下图中的iterator.remove() //删除当前遍历的这个元素为什么不要使用集合...

weixin_39542477的博客 195

锂电池充电器电路设计 里面有电路

锂电池充电器电路设计 里面有电路 3.7V升压到5V电路设计。

廖雪峰Python教程[完整版]

廖雪峰的python教程整理的,已经排好版了,而且还是完整的,适合小白

foreach里不能list.remove(i)的原因

通俗点理解就是 你有一个游戏账号,每天都得进行签到操作,第一天,你进行了签到,实际签到天数为1(modCount),而你脑子里认为的签到过的次数(expectedModCount)也为1,这并没有什么问题,然而,第二当你想要进行签到的时候,你发现你的实际签到天数居然变成了两天,这与你印象中的签到次数不一致(modCount!我们第一次调用获取到"1号"并删除时,是正常的,但是在remove的时候,他调用的是list.remove 自身的remove。=size,为真,执行next。

Zwwxd666的博客 1285

SAP B1中文培訓教材_SDK

公司内部培训资料,对开发工具 ,DIAPI, UIAPI,Add-ON有详细解说

List遍历删除元素(使用迭代器)

List使用froEach遍历删除元素报错java.util.ConcurrentModificationException

阳光男孩的博客 686

java 遍历list并删除_Java遍历List并删除某些元素

Java遍历List并删除某些元素​在阿里的Java编程规约中有一条:【强制】不要在foreach循环里进行元素的remove/add操作。remove元素请使用Iterator方式,如果并发操作,需要对Iterator对象加锁。​这里不禁要问为什么?​首先来试一下,遍历List时删除元素究竟行不行:public class IteratorTest {public static void sin...

weixin_39594457的博客 619

java集合中如何修改元素_java 如何实现正确的删除集合中的元素

在java中如果我们需要遍历集合并删除其中的某些元素时,例如对于List来说,我们有三种办法。1. 普通的for循环遍历并删除public void forRemove(Listlist, T obj){for(int i = 0;i < list.size(); i++){if (obj == list.get(i)){list.remove(obj);}}}main中调用Listlist...

weixin_29738537的博客 3206

Java集合中不要在 foreach 循环里进行元素的 remove/add 操作

强制】不要在foreach循环里进行元素的remove/add操作。remove元素请使用Iterator。方式,如果并发操作,需要对Iterator对象加锁。

weiambt的博客 657

java删除集合元素吗_java 如何实现正确的删除集合中的元素

在java中如果我们需要遍历集合并删除其中的某些元素时,例如对于List来说,我们有三种办法。1. 普通的for循环遍历并删除public void forRemove(List list, T obj){for(int i = 0;i < list.size(); i++){if (obj == list.get(i)){list.remove(obj);}}}main中调用List li...

weixin_42511517的博客 223

java list移除符合条件的元素_关于List的remove()方法陷阱,你可能没遇到过

小爱今天去面试了,有一道笔试题没有答对,估计黄了。题目是这样的1Listlist=newArrayList<>();2list.add(1);3list.add(2);4for(Integertemp:list){5if(1==temp){6list.remove(temp);7}8}9System.out.println(list);...

weixin_36265390的博客 937

如何删除List中的重复元素

作为一名菜鸟,经常犯一些不可思议的错误,为了能让自己能不在犯低级错误, 也能让大佬指导一下我,遂记录以分享之。 复制代码 一个List中现在有1——10的元素若干个,需要删除指定名称为3的元素,分别打印删除前和删除后的list。 看到这个题目我的思路是循环遍历list,在遍历的时候,判断符合删除条件的元素,remove掉,这样就能删除掉list中所有符合删除条件的元素。 复制代码 代码如...

weixin_34304013的博客 512

List 循环中出现的问题

使用List遇到的题在使用List的时,不要在foreach循环中不要对List元素进行add/remove操作。 如果你使用的话,非常有可能会报错Java.util.ConcurrentModificationException 错误原因 调用list.remove()方法导致modCount和expectedModCount的值不一致。如果你想要使用 要使用它的迭代器Iterator,用在多

yanshihao3的博客 396

JAVA中循环删除list中元素的方法总结

原文地址  https://www.cnblogs.com/pcheng/p/5336903.html JAVA中循环遍历list有三种方式for循环、增强for循环(也就是常说的foreach循环)、iterator遍历。 1、for循环遍历list for(int i=0;i&lt;list.size();i++){ if(list.get(i).equals("del"))...

lenkee的博客 2561

【JAVA笔记——术】JAVA LIST DEL遍历方式研究

在Java中有时候我们会需要对List里面的符合某种业务的数据进行删除,但是如果不了解里面的机制就容易掉入“陷阱”导致遗漏或者程序异常。本文以代码例子的方式进行说明该问题。 1、采用索引下标遍历的方式 我们看这段示例代码: view source print? 1 public class ListRemoveTest {

Contributor -> Committer 699

java.util.ConcurrentModificationException=null

我的错误原因是在forEach循环list的时候,并且在多线程场景下使用remove()移除元素: 搜索解决办法: 使用for(int i=0;i<a.size;i++)失败 使用Iterator遍历list,不报ConcurrentModificationException的错误了,报多线程异常。很难了!!! 解决办法: 使用new CopyOnWriteArrayList<>(list); 将list放入CopyOnWriteArrayList中,使用新的list进行遍历移除就可以了,

sjgllllll的博客 675

Java集合遍历时进行remove报错

以ArrayList举例讲解,对于遍历list集合,一般有两种方式,第一种直接用数组下标标遍历,第二种用forEach遍历,也就是用ArrayList的内部类Itr遍历,该内部实现了Iterator接口,也就是常说的迭代器,无论是哪种方式,都不要在遍历过程中用list自身的remove方法进行操作,第二种方式可能会抛出java.util.ConcurrentModificationExceptio...

cdtyty的博客 1469
上一篇: 一文普及 Git 使用与常用命令整理
下一篇: 【踩坑记录】关于“保留两位小数”导致的Crash
青杉`
博客等级 码龄10年 148粉丝 39原创
评论
成就一亿技术人!
拼手气红包6.0元
还能输入1000个字符
 
 条评论被折叠 查看
添加红包

请填写红包祝福语或标题

个

红包个数最小为10个

元

红包金额最低5元

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

抵扣说明:

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

余额充值