ArrayList的forEach比传统for循环慢10%–20%,因其本质调用iterator()创建迭代器,每次循环需执行hasNext()、next()方法调用,含对象创建、volatile校验及checkcast类型转换开销;而传统for直接索引访问get(),时间复杂度O(1)且无额外对象与方法调用。

ArrayList 的 forEach 方法(即 list.forEach(action))比传统 for 循环略慢,但差距通常在 10%–20% 之间,具体取决于数据量和 JVM 版本。
forEach 方法本质是迭代器调用
它底层调用的是 ArrayList.iterator(),再通过 Iterator 的 hasNext() 和 next() 方法逐个消费元素。每次循环都涉及:
- 方法调用开销(
hasNext、next) - 对象创建(首次调用时生成迭代器实例)
- 泛型类型擦除后的强制转换(如
checkcast字节码指令)
传统 for 循环直接索引访问
使用 for (int i = 0; i 的方式:
- 跳过迭代器对象创建和接口方法调用
- 直接触发
ArrayList.get(i)—— 底层是数组下标访问,O(1),无额外判断 - 若提前缓存
size(如int len = list.size()),还能避免每次循环重复调用size()
性能差异随数据量放大
小数据量(如 1 万以内)几乎无感;但到百万级时,实测典型差距如下(JDK 17,OpenJDK):
立即学习“Java免费学习笔记(深入)”;
- 100 万元素:传统 for 约快 15%–18%
- 1000 万元素:传统 for 可快 20%–25%
- 差距主因不是逻辑复杂度,而是函数调用与对象生命周期开销累积
实际开发中不必过度纠结
除非处于高频核心路径(如每秒调用数万次的实时计算、游戏帧逻辑、金融高频报价处理),否则这点差异远小于一次日志输出或字符串拼接的开销。可读性、意图表达和维护成本更关键:
- 需修改元素或依赖索引?选传统 for
- 仅遍历并执行副作用(如打印、入库、发消息)?
forEach语义更清晰 - 团队统一风格优先于微小性能收益



















