必须用 Iterator 而不能用 for 循环的情况是遍历中需删除元素,因 Iterator.remove() 是唯一安全机制,其他方式会抛 ConcurrentModificationException。

什么时候必须用 Iterator 而不能用 for 循环
当需要在遍历过程中删除集合元素时,Iterator 是唯一安全的选择。直接用增强 for 循环(for (T t : list))或传统 for 索引循环调用 list.remove(),会触发 ConcurrentModificationException。
-
Iterator.remove()是唯一被设计为在迭代中安全删除元素的机制 - 增强
for循环底层就是用Iterator实现的,但它隐藏了remove()方法,所以无法调用 - 手动用索引
for (int i = 0; i 删除时,容易漏掉下一个元素(因为索引前移),也需额外处理i--
Iteratorit = list.iterator(); while (it.hasNext()) { String s = it.next(); if (s.startsWith("tmp")) { it.remove(); // 安全删除 } }
for-each 和 Iterator 在性能和语义上的实际差异
对大多数集合(如 ArrayList、LinkedList),for-each 和显式 Iterator 的性能几乎一致——因为前者编译后就是后者;但语义不同:
-
for-each更简洁,适合只读遍历,且代码意图明确 - 显式
Iterator多了一层对象创建开销(微乎其微),但换来对遍历过程的完全控制(比如提前break后还能继续用同一Iterator?不能,它是一次性的) -
Iterator可以配合try-with-resources(仅限实现了AutoCloseable的自定义迭代器,标准 JDK 迭代器不支持)
传统索引 for 循环该用在哪些场景
不是所有遍历都适合抽象成“逐个访问”,当逻辑依赖索引本身时,传统 for 不可替代:
- 需要同时访问当前元素和相邻元素(如比较
list.get(i)和list.get(i+1)) - 按步长遍历(
i += 2)、反向遍历(i = list.size()-1; i >= 0; i--) - 批量操作:从索引
5开始截取后半段,或复制某段区间到新数组 - 对
ArrayList随机访问快,但对LinkedList调用get(i)是 O(n) —— 此时强行用索引for会严重拖慢性能
容易被忽略的兼容性与泛型细节
Java 5 引入泛型后,Iterator 和 for-each 都要求集合声明了正确类型;但绕过泛型(原始类型)会导致运行时问题:
立即学习“Java免费学习笔记(深入)”;
- 用原始
List声明 +for-each,编译通过但可能抛ClassCastException -
Iterator的next()返回Object,若没加泛型,需手动强转,失去编译期检查 - 某些老框架返回
Enumeration(如request.getParameterNames()),不能直接用于for-each,必须用while (e.hasMoreElements())
真正麻烦的不是选哪个语法,而是理解「谁拥有遍历权」——是集合自己控制(for-each)、你手动掌控(Iterator),还是你要拿捏下标(索引 for)。选错往往不是性能问题,而是删错元素、跳过数据、或在 LinkedList 上写出 O(n²) 遍历。










