面试官:for vs foreach,什么时候选谁?(附图解)
理解语法糖、迭代器与性能差异
形式:对话 + 图解 + 代码实验
场景:面试 & 代码优化
引言
面试官老王:小叶,项目里遍历集合你用 for
还是 foreach
?为什么?
候选人小叶:先看 原理 & 场景 再决定!
1. 对话 1:编译后长啥样?
面试官:增强 for
是语法糖吗?
小叶:是的!
for(String s : list){ ... }
编译后等价:
for(Iterator<String> it = list.iterator(); it.hasNext();){
String s = it.next();
...
}
✔️ 对话 1
2. 对话 2:下标随机访问还能用 foreach 吗?
面试官:我想要索引值怎么办?
小叶:普通 for (int i=0;i<list.size();i++)
能直接拿 i
;foreach 拿不到索引,但可以用 AtomicInteger
或流式 IntStream.range()
补救。
✔️ 对话 2
3. 对话 3:删除元素风险?
面试官:遍历时删除元素,两种写法都安全?
小叶:
- 普通
for
用下标可安全删除,但需手动i--
调整。 - foreach 背后迭代器删除需
it.remove()
;直接list.remove()
会触发ConcurrentModificationException
。
✔️ 对话 3
4. 性能对比实验
long t1 = System.nanoTime();
for(int i=0;i<arrayList.size();i++){ sum += arrayList.get(i); }
long t2 = System.nanoTime();
for(Integer v: arrayList){ sum2 += v; }
long t3 = System.nanoTime();
System.out.println((t2-t1)+","+(t3-t2));
- ArrayList:普通
for
调用get(i)
O(1),几乎同速。 - LinkedList:
get(i)
O(n),普通for
极慢;foreach 走迭代器 O(n)。
5. 内部流程图
graph LR
A[增强 for] --> B[编译期展开]
B --> C[Iterator.hasNext()]
C --> D[Iterator.next()]
6. 选择建议
场景 | 推荐循环 | 理由 |
---|---|---|
需索引/随机访问 | for | 直接用 i ,ArrayList 高效 |
遍历 LinkedList | foreach | 迭代器顺序访问 |
删除元素频繁 | Iterator 手动循环 | remove() 安全 |
7. 总结口诀
增强 for 省代码,底层还是迭代器;需要下标用普通 for,链表遍历靠迭代器!