for-each循环能替代传统for循环中遍历iterable集合和数组的写法,如for(int i=0;i

for-each 循环能替代哪些传统 for 写法
它专用于遍历实现了 Iterable 接口的集合(如 ArrayList、HashSet)和数组,不能用来修改集合结构(比如边遍历边 remove()),也不能直接获取当前索引。常见被替代的写法包括:
- 用
for (int i = 0; i 配合 <code>list.get(i) - 用
Iterator显式调用hasNext()和next()
这两类写法在只读场景下都显得啰嗦,且容易因手误写错边界条件或漏掉
next() 调用。
for-each 的语法结构和类型推导陷阱
基本形式是 for (Type element : collection),其中 Type 必须与集合元素类型一致(或其父类)。Java 不支持自动泛型擦除后的类型推导——比如你写 for (String s : list),而 list 是 ArrayList<object></object>,编译会报错,不是运行时 ClassCastException。
常见错误现象:
- “incompatible types: Object cannot be converted to String” —— 源集合没声明泛型,或用了原始类型(
new ArrayList()) - 想遍历时修改元素值,却发现只是改了局部变量
element,原集合不变(因为是值拷贝,对引用类型也只是拷贝了引用)
所以务必确保集合带正确泛型声明,且别指望靠 for-each 改集合内容。
什么情况下不能用 for-each,得退回传统方式
有三类典型场景必须绕开 for-each:
- 需要访问当前索引(比如要跳过第 0 个元素,或做下标相关计算)→ 改用传统
for (int i = 0; ...) - 遍历中要删除元素 → 必须用
Iterator.remove(),否则抛ConcurrentModificationException;for-each 底层就是 Iterator,但不暴露 remove 方法 - 遍历数组的同时还要修改数组内容(非集合)→ for-each 只读,改数组得用下标
一个具体例子:过滤掉空字符串并收集到新列表,不能写成
for (String s : list) { if (s.isEmpty()) list.remove(s); } —— 这会崩,必须用 Iterator 或先收集待删项再批量删。
性能差异其实可以忽略,但要注意装箱/拆箱开销
for-each 编译后就是传统 Iterator 调用,和手写 Iterator 性能几乎无差别。真正影响性能的是隐式操作:
- 遍历
ArrayList<integer></integer>时,每次取出来的Integer要拆箱成int才能参与计算,如果循环体里频繁算术运算,建议改用IntStream或原始类型数组 - 遍历
LinkedList时,for-each 比传统下标访问(get(i))快得多,因为后者是 O(n) 复杂度,而 Iterator 是 O(1)
所以别为了“语法糖”盲目替换,先看集合类型和访问模式。
最容易被忽略的一点:for-each 对 null 集合直接抛 NullPointerException,不会像某些工具方法那样静默处理。上线前记得检查集合是否为 null,或者统一用 Objects.requireNonNull(collection) 提前暴露问题。










