增强for循环仅支持只读操作,修改集合结构必须使用iterator的remove()方法;多线程环境下需选用线程安全集合或加锁;遍历时添加元素须缓存后统一处理。

Java 集合遍历看似简单,但用错方式容易抛 ConcurrentModificationException 或漏删、重复处理元素。核心在于:**增强 for 循环只读安全;真要改结构(如删除),必须用 Iterator 的 remove() 方法**。
增强 for 循环适合快速读取,但不能改集合结构
它本质是编译器自动展开为 Iterator 调用,写法简洁,可读性强,但完全隐藏了迭代器对象——也就无法调用 remove()。一旦在循环体里直接调用 list.remove() 或 set.add(),运行时必然触发并发修改异常。
- ✅ 安全场景:打印、计算、校验、转 DTO 等只读操作
- ❌ 危险操作:任何调用集合自身增删清空方法的行为(
add、remove、clear) - ⚠️ 注意:即使只是修改临时变量(如
str.toUpperCase()),也不会影响原集合中的字符串对象(String 不可变),但若元素是可变对象(如自定义 User 类),修改其属性是允许的,不触发异常
Iterator 是唯一安全删除的途径
它提供显式控制能力,通过 hasNext() 和 next() 推进,再用 remove() 删除上一次 next() 返回的元素。这个 remove 是同步维护内部游标状态的,不会破坏遍历一致性。
- 必须先调用
next(),才能调用remove();否则抛IllegalStateException - 每次
next()后最多只能调用一次remove();重复调用也抛异常 - 支持边遍历边删,无需额外缓存待删项,代码更直观
多线程环境要额外防护
普通 ArrayList 或 HashMap 的迭代器是“快速失败”(fail-fast)的:只要其他线程在你遍历时修改了集合结构(哪怕只是 add 一个元素),当前迭代器立刻抛异常。
- 读多写少场景 → 选用
CopyOnWriteArrayList(遍历时复制底层数组,安全但写操作开销大) - 高并发读写 → 用
ConcurrentHashMap或ConcurrentLinkedQueue,它们支持弱一致性遍历 - 不得已用普通集合 → 对整个遍历块加
synchronized锁(注意锁粒度,避免阻塞太久)
遍历时添加元素需绕道处理
无论 Iterator 还是增强 for,都不支持在遍历过程中向原集合添加新元素——这会彻底打乱迭代器内部计数逻辑,导致不可预测行为(跳过、重复、异常)。
- 正确做法:先用 List 或 Set 缓存待添加的元素,遍历结束后统一
addAll() - 若逻辑强依赖“边遍历边生成并加入”,考虑改用队列 + while 循环(如 BFS 场景),或拆分为两轮:第一轮收集,第二轮添加+处理
- 特别注意:
forEach()方法(Stream API 中的)同样禁止修改原集合,且不保证执行顺序,慎用于有状态操作
Java免费学习笔记:立即使用
解锁 Java 大师之旅:从入门到精通的终极指南











