foreach 是 Iterator 的语法糖,编译后转为 hasNext() 和 next() 调用;遍历 ArrayList 时三者性能几乎无差别;边遍历边删除必须用 Iterator.remove();ConcurrentHashMap 的 Iterator 具有弱一致性;禁止在 for 循环内重复创建 Iterator。

foreach 就是 Iterator 的语法糖,别被表象骗了
Java 编译器会把 for (String s : list) 直接翻译成等效的 Iterator 调用:hasNext() + next()。字节码里根本不存在“foreach 指令”,它只是写法更简洁而已。所以性能上三者(for、foreach、手写 Iterator)在遍历 ArrayList 时几乎无差别——真正拖慢速度的,是开发者自己写的低效逻辑,比如在循环体内反复调用 list.iterator() 或每次迭代都查 list.size()。
边遍历边删元素,只有 Iterator.remove() 是安全的
用 for 循环遍历时调 list.remove(i) 或 list.remove(obj),大概率会漏删、重复删或抛 IndexOutOfBoundsException;用 foreach 直接删会触发 ConcurrentModificationException——因为它的底层 Iterator 检测到 modCount 被外部修改了。唯一安全的方式是:
- 拿到
Iterator实例后,只调用它的remove()方法(必须在next()之后调用) - 不能在
next()前或连续两次调remove(),否则抛IllegalStateException
示例:
Iteratorit = list.iterator(); while (it.hasNext()) { String s = it.next(); if ("target".equals(s)) it.remove(); // ✅ 安全 }
并发读多写少?Iterator 的“弱一致性”不是 bug 是设计
ConcurrentHashMap 的 keySet().iterator()、values().iterator() 全部是弱一致的:它不阻塞写操作,也不被写操作阻塞,遍历时可能看到部分更新、看不到新增、甚至跳过刚删除的项。这不是缺陷,而是为高吞吐读场景做的取舍。如果你需要强一致性(比如导出快照),得换方式:
- 用
collection.toArray()获取当前瞬间副本(注意内存开销) - 加锁后手动复制再遍历(影响并发度)
- 改用
CopyOnWriteArrayList(仅适用于读远多于写的极小列表)
别在 for 循环里手动 new Iterator,那是典型反模式
下面这种写法看着像“用了 Iterator”,实则灾难:
for (int i = 0; i < list.size(); i++) {
Iterator it = list.iterator(); // ❌ 每次都新建,O(n²) 时间!
while (it.hasNext()) {
System.out.println(it.next());
}
} 它让本该 O(n) 的遍历变成 O(n²),还白白触发多次 modCount 校验。真要用 Iterator,就老老实实写一次初始化、一次 while 循环;想省事,直接用 foreach——它自动帮你做了正确封装。
最常被忽略的一点:所有基于 Iterator 的遍历(包括 foreach)都依赖 modCount 快照机制,一旦集合被非迭代器途径修改,下一次 next() 就会炸。这不是线程安全问题,而是单线程里“自己改自己”也会触发——这点比很多人想的更严格。
立即学习“Java免费学习笔记(深入)”;










