0

0

如何解决Java集合遍历时的修改异常_Iterator.remove方法应用

P粉602998670

P粉602998670

发布时间:2026-03-05 13:16:03

|

119人浏览过

|

来源于php中文网

原创

concurrentmodificationexception 是 java 集合的 fail-fast 机制抛出的异常,用于检测单线程中遍历时非法修改结构(如 for-each 中直接调 remove),其根源是迭代器的 expectedmodcount 与集合 modcount 不一致;正确做法是用 iterator.remove()(需先 next())、removeif()(jdk 8+,注意 predicate 纯函数性)或线程安全容器。

如何解决java集合遍历时的修改异常_iterator.remove方法应用

ConcurrentModificationException 是什么,为什么不能直接用 for 循环删元素

Java 集合(比如 ArrayListHashMap)在遍历时检测到结构被意外修改,就会抛 ConcurrentModificationException。这不是线程安全问题,而是 fail-fast 机制主动报错——哪怕单线程里边遍历边调 list.remove(obj),也会崩。

根本原因是:迭代器内部维护了一个 expectedModCount,和集合自身的 modCount 对不上就炸。for-each 底层就是用的 Iterator,所以 for (String s : list) { if (s.isEmpty()) list.remove(s); } 必然失败。

  • 别用 for-each 或普通 for (int i = 0; ...) 边遍历边调 list.remove()
  • removeIf() 是安全的,但它是 JDK 8+ 才有,且底层仍依赖迭代器的 remove()
  • 如果必须兼容老版本或需要更细粒度控制(比如删完还要 break),就得手动拿 Iterator

Iterator.remove() 的唯一正确写法

Iterator.remove() 是迭代器自己提供的删除方法,它会同步更新 expectedModCount,所以不会触发异常。但它有个硬性前提:必须在 next() 之后调用,且只能调一次。

常见错误写法:it.remove() 放在 it.next() 前、连着调两次、或者在没调 next() 的空迭代器上调用 —— 全都会抛 IllegalStateException

立即学习Java免费学习笔记(深入)”;

  • 必须先 it.next() 拿到当前元素,再判断是否要删,再 it.remove()
  • 不能在同一个 next() 后反复调 remove()
  • 不能在刚创建迭代器后、还没 next() 就调 remove()

示例:

Designs.ai
Designs.ai

AI设计工具

下载
Iterator<String> it = list.iterator();
while (it.hasNext()) {
    String s = it.next(); // 必须先 next()
    if (s == null || s.trim().isEmpty()) {
        it.remove(); // 此时 remove 合法
    }
}

removeIf() 看似简单,但要注意 Predicate 的副作用

List.removeIf(Predicate) 写起来最简洁,JDK 8+ 直接一行解决。但它内部仍是用 Iterator + remove() 实现的,所以语义一致、线程不安全、同样 fail-fast。

真正容易踩的坑是 Predicate 本身带状态或副作用。比如你在 lambda 里改了外部变量、调了远程接口、或者用了可变对象做判断依据,结果可能和预期不符,尤其当集合很大、JVM 优化或并发场景下更难复现。

  • 确保 Predicate 是纯函数:只读输入,不改外部状态
  • 避免在 removeIf() 的 lambda 里调用可能抛异常的方法(异常发生时已删部分元素,无法回滚)
  • removeIf() 返回 boolean 表示“是否有元素被删”,但不告诉你删了几个,需要统计得另计

安全示例:

list.removeIf(s -> s != null && s.length() < 3);

多线程环境下 Iterator.remove() 不管用

上面所有方案都只解决单线程下的结构修改异常。一旦多个线程同时读写同一个 ArrayList,即使你严格用 Iterator.remove(),依然可能出错 —— 因为 modCount 变量不是 volatile,且 remove() 本身不是原子操作。

这时候不能靠“怎么删”,而得换容器。别试图加锁包装普通集合,性能差还易死锁。

  • 读多写少:用 Collections.unmodifiableList() + 外部同步,或换成 CopyOnWriteArrayList(注意写操作开销大)
  • 读写均衡:考虑 ConcurrentLinkedQueue(无序)或 ConcurrentHashMap(按 key 查)
  • 真要线程安全的动态列表且需索引访问?老实手写锁或用 ReentrantLock 包一层 ArrayList,但得自己保证所有访问路径都被覆盖

一句话:Iterator 的安全,只对单线程内的“顺序修改”有效;跨线程,它连入场券都不发。

热门AI工具

更多
DeepSeek
DeepSeek

幻方量化公司旗下的开源大模型平台

豆包大模型
豆包大模型

字节跳动自主研发的一系列大型语言模型

通义千问
通义千问

阿里巴巴推出的全能AI助手

腾讯元宝
腾讯元宝

腾讯混元平台推出的AI助手

文心一言
文心一言

文心一言是百度开发的AI聊天机器人,通过对话可以生成各种形式的内容。

讯飞写作
讯飞写作

基于讯飞星火大模型的AI写作工具,可以快速生成新闻稿件、品宣文案、工作总结、心得体会等各种文文稿

即梦AI
即梦AI

一站式AI创作平台,免费AI图片和视频生成。

ChatGPT
ChatGPT

最最强大的AI聊天机器人程序,ChatGPT不单是聊天机器人,还能进行撰写邮件、视频脚本、文案、翻译、代码等任务。

相关专题

更多
string转int
string转int

在编程中,我们经常会遇到需要将字符串(str)转换为整数(int)的情况。这可能是因为我们需要对字符串进行数值计算,或者需要将用户输入的字符串转换为整数进行处理。php中文网给大家带来了相关的教程以及文章,欢迎大家前来学习阅读。

930

2023.08.02

java中boolean的用法
java中boolean的用法

在Java中,boolean是一种基本数据类型,它只有两个可能的值:true和false。boolean类型经常用于条件测试,比如进行比较或者检查某个条件是否满足。想了解更多java中boolean的相关内容,可以阅读本专题下面的文章。

366

2023.11.13

java boolean类型
java boolean类型

本专题整合了java中boolean类型相关教程,阅读专题下面的文章了解更多详细内容。

42

2025.11.30

if什么意思
if什么意思

if的意思是“如果”的条件。它是一个用于引导条件语句的关键词,用于根据特定条件的真假情况来执行不同的代码块。本专题提供if什么意思的相关文章,供大家免费阅读。

839

2023.08.22

java中break的作用
java中break的作用

本专题整合了java中break的用法教程,阅读专题下面的文章了解更多详细内容。

120

2025.10.15

java break和continue
java break和continue

本专题整合了java break和continue的区别相关内容,阅读专题下面的文章了解更多详细内容。

261

2025.10.24

string转int
string转int

在编程中,我们经常会遇到需要将字符串(str)转换为整数(int)的情况。这可能是因为我们需要对字符串进行数值计算,或者需要将用户输入的字符串转换为整数进行处理。php中文网给大家带来了相关的教程以及文章,欢迎大家前来学习阅读。

930

2023.08.02

int占多少字节
int占多少字节

int占4个字节,意味着一个int变量可以存储范围在-2,147,483,648到2,147,483,647之间的整数值,在某些情况下也可能是2个字节或8个字节,int是一种常用的数据类型,用于表示整数,需要根据具体情况选择合适的数据类型,以确保程序的正确性和性能。本专题为大家提供相关的文章、下载、课程内容,供大家免费下载体验。

603

2024.08.29

Rust内存安全机制与所有权模型深度实践
Rust内存安全机制与所有权模型深度实践

本专题围绕 Rust 语言核心特性展开,深入讲解所有权机制、借用规则、生命周期管理以及智能指针等关键概念。通过系统级开发案例,分析内存安全保障原理与零成本抽象优势,并结合并发场景讲解 Send 与 Sync 特性实现机制。帮助开发者真正理解 Rust 的设计哲学,掌握在高性能与安全性并重场景中的工程实践能力。

2

2026.03.05

热门下载

更多
网站特效
/
网站源码
/
网站素材
/
前端模板

精品课程

更多
相关推荐
/
热门推荐
/
最新课程
Kotlin 教程
Kotlin 教程

共23课时 | 4.1万人学习

C# 教程
C# 教程

共94课时 | 10.7万人学习

Java 教程
Java 教程

共578课时 | 77.3万人学习

关于我们 免责申明 举报中心 意见反馈 讲师合作 广告合作 最新更新
php中文网:公益在线php培训,帮助PHP学习者快速成长!
关注服务号 技术交流群
PHP中文网订阅号
每天精选资源文章推送

Copyright 2014-2026 https://www.php.cn/ All Rights Reserved | php.cn | 湘ICP备2023035733号