普通for循环不越界的关键是索引范围为0到size()-1(ArrayList)或length-1(数组),即for(int i=0; i

普通for循环怎么写才不越界
普通for循环的核心是手动控制索引,最容易出错的是边界条件——尤其是遍历ArrayList或数组时用而不是<code>,导致<code>IndexOutOfBoundsException。
常见错误现象:for (int i = 0; i —— 最后一次迭代访问<code>list.get(list.size()),必然抛异常。
- 正确写法永远是
i (数组同理:<code>i ) - 如果要倒序遍历,起始值用
list.size() - 1,条件用i >= 0,别漏减一 - 修改集合(如
remove())时,普通for可能跳过元素——因为索引前移了,但循环变量照常+1
增强for循环(for-each)能用在哪些地方
增强for本质是语法糖,背后调用Iterator,所以它只适用于实现了Iterable接口的类型(List、Set、Map.keySet()、Map.values()等),**不能直接遍历Map本身**,也不能获取当前索引。
使用场景:只读遍历、逻辑简单、不需要下标或修改集合结构。
立即学习“Java免费学习笔记(深入)”;
- 安全:不会因索引计算错误崩溃,也不容易在遍历时意外修改结构(虽然仍可能触发
ConcurrentModificationException) - 限制:无法在循环中删除元素(
iterator.remove()除外),也不能同时访问前后相邻元素 - 数组也能用:
for (String s : stringArray),底层按元素复制,对基本类型数组也有效
for-each和普通for性能差多少
差异极小,但有明确倾向:普通for在随机访问集合(如ArrayList)时略快;而for-each在链表类(如LinkedList)上更稳——因为它用Iterator逐个推进,避免了get(i)每次从头遍历。
-
ArrayList:普通for快约5%~10%,但实际业务中几乎感知不到 -
LinkedList:普通for用get(i)是O(n²),for-each是O(n),差距巨大 - 编译后,
for-each被转成带Iterator的普通循环,无额外对象创建开销(JDK 7+)
什么时候必须用普通for,不能用for-each
当需要索引、需要修改集合结构、或需要精确控制迭代步长时,for-each就无能为力了。
典型错误尝试:for (String s : list) { if (s.isEmpty()) list.remove(s); } —— 这会抛ConcurrentModificationException,而且删不干净。
- 需要下标:比如构建新数组
newArr[i] = oldArr[i] * 2,或记录首次匹配位置 - 需要跳过/回退:比如解析协议时遇到分隔符就
i += 2 - 需要安全删除:用
Iterator.remove(),或倒序普通for(list.remove(i)不影响前面索引)
普通for的边界、索引管理和并发修改风险,是实际写错最多的地方;而for-each看似简单,一旦误用于Map或想边遍历边删,问题就藏得深。


















