面試高頻陷阱:for vs foreach,你真的分清了嗎?
面试高频陷阱:for vs foreach,你真的分清了吗?
引子:一次线上故障引发的思考
上个月,我们系统突然出现了性能问题,CPU使用率飙升到90%。排查后发现,罪魁祸首竟然是一段看似"无害"的foreach循环!
那段代码的作者振振有词:"foreach不是比传统for循环更优雅、更安全吗?"这句话让我想起了自己刚工作时的天真想法——以为foreach就是for的完美替代品。
探索:两种循环的"真面目"
传统for:老兵不死
传统for循环就像是一把瑞士军刀,虽然看起来朴素,但功能强大,控制精确:
List<String> list = Arrays.asList("Java", "Python", "Go");
// 传统for:完全控制
for (int i = 0; i < list.size(); i++) {
String lang = list.get(i);
// 可以获取索引,可以倒序,可以跳跃...
if (i % 2 == 0) {
System.out.println("偶数位置:" + lang);
}
}
Enhanced for:优雅但有限制
Enhanced for(foreach)就像是自动档汽车,开起来舒服,但失去了一些控制权:
// foreach:简洁优雅
for (String lang : list) {
System.out.println("语言:" + lang);
// 但是...拿不到索引,不能反向遍历
}
转折:踩坑瞬间
第一个坑:性能陷阱
还记得开头提到的线上故障吗?问题就出在这里:
// 看似无害的foreach,实际是性能杀手
LinkedList<Integer> linkedList = new LinkedList<>();
// ... 添加10万个元素
// 这行代码让CPU哭泣 😭
for (int i = 0; i < linkedList.size(); i++) {
Integer value = linkedList.get(i); // 每次get(i)都是O(n)操作!
// ...
}
LinkedList的get(i)方法需要从头开始遍历,时间复杂度是O(n),整个循环就变成了O(n²)!
第二个坑:修改元素的陷阱
List<String> fruits = new ArrayList<>(Arrays.asList("苹果", "香蕉", "坏橘子"));
// 危险操作:在foreach中删除元素
for (String fruit : fruits) {
if (fruit.contains("坏")) {
fruits.remove(fruit); // 💥 ConcurrentModificationException
}
}
解决:选择的智慧
性能对比真相
场景 | 传统for | foreach | 推荐 |
---|---|---|---|
ArrayList遍历 | 快 | 快 | foreach(可读性好) |
LinkedList遍历 | 极慢 | 快 | foreach |
需要索引 | ✅ | ❌ | 传统for |
修改集合 | ✅ | ❌ | 传统for |
纯遍历 | ✅ | ✅ | foreach |
安全删除的正确姿势
// 方案1:传统for倒序删除
for (int i = fruits.size() - 1; i >= 0; i--) {
if (fruits.get(i).contains("坏")) {
fruits.remove(i);
}
}
// 方案2:Iterator(foreach底层就是这个)
Iterator<String> iterator = fruits.iterator();
while (iterator.hasNext()) {
if (iterator.next().contains("坏")) {
iterator.remove(); // 安全删除
}
}
经验启示
选择原则
用foreach的场景:
- 纯粹的遍历操作
- 不需要索引信息
- 追求代码简洁性
- 集合类型是ArrayList、HashSet等
用传统for的场景:
- 需要索引操作
- 要修改集合结构
- 性能敏感且使用LinkedList
- 需要复杂的循环控制
面试反杀技巧
当面试官问"for和foreach有什么区别"时,别只说语法差异,直接抛出这几个点:
- 底层实现:foreach是语法糖,编译后变成Iterator
- 性能差异:LinkedList场景下的巨大差异
- 安全性:ConcurrentModificationException的产生和避免
- 适用场景:具体场景具体分析
踩坑教训
- 不要盲目追求"优雅":代码优雅不等于性能优秀
- 了解集合特性:ArrayList和LinkedList的内部实现差异巨大
- 测试驱动选择:性能敏感场景要做基准测试
总结
for和foreach的选择,表面上是语法问题,实际上考验的是对Java集合框架的深度理解。
记住这个口诀:纯遍历用foreach,要索引用for,LinkedList慎用传统for,修改集合选Iterator。
最重要的是,不要被"新语法更好"的刻板印象束缚。技术选型的核心永远是:场景适配,性能优先。
點(diǎn)擊查看更多內(nèi)容
為 TA 點(diǎn)贊
評(píng)論
評(píng)論
共同學(xué)習(xí),寫下你的評(píng)論
評(píng)論加載中...
作者其他優(yōu)質(zhì)文章
正在加載中
感謝您的支持,我會(huì)繼續(xù)努力的~
掃碼打賞,你說(shuō)多少就多少
贊賞金額會(huì)直接到老師賬戶
支付方式
打開(kāi)微信掃一掃,即可進(jìn)行掃碼打賞哦