Java循环对决:for vs foreach,谁是你的最佳选择?

当循环开始"内卷"

想象你要清点一个仓库:
🔢 for循环 → 拿着清单逐个核对(自己控制每个步骤)
🚀 foreach循环 → 智能机器人自动扫描(全自动遍历)

Java中的这两种循环就像不同的清点方式,今天我们就来揭秘它们的区别和最佳使用场景!


一、基本语法对比

45%50%5%Java开发者循环使用偏好传统for循环增强for循环其他循环

1. 传统for循环

for (初始化; 条件; 步进) {
    // 循环体
}

// 数组遍历示例
int[] nums = {1, 2, 3};
for (int i = 0; i < nums.length; i++) {
    System.out.println(nums[i]);
}

2. 增强for循环(foreach)

for (元素类型 变量名 : 集合或数组) {
    // 循环体
}

// 同数组的foreach遍历
for (int num : nums) {
    System.out.println(num);
}

二、核心区别五维分析

维度for循环foreach循环
控制权完全掌控索引自动迭代
可读性较冗长简洁直观
修改集合可安全删除元素遍历时修改会抛异常
性能数组遍历略快集合遍历更优
适用场景需要索引/复杂控制简单遍历

三、使用场景对决

1. for循环擅长场景

// 场景1:需要索引时
for (int i = 0; i < list.size(); i++) {
    System.out.println(i + ": " + list.get(i));
}

// 场景2:逆序遍历
for (int i = array.length - 1; i >= 0; i--) {
    System.out.println(array[i]);
}

// 场景3:间隔访问
for (int i = 0; i < 100; i += 5) {
    System.out.println(i);
}

2. foreach循环擅长场景

// 场景1:简单集合遍历
List<String> names = Arrays.asList("Alice", "Bob");
for (String name : names) {
    System.out.println(name);
}

// 场景2:多维数组
int[][] matrix = {{1,2}, {3,4}};
for (int[] row : matrix) {
    for (int num : row) {
        System.out.print(num + " ");
    }
}

// 场景3:实现Iterable的自定义类
for (Product p : shoppingCart) { // 购物车实现Iterable
    p.display();
}

四、性能对比实测

1. 数组遍历测试

数组遍历性能对比(百万次)
在这里插入图片描述

int[] array = new int[10_000_000];

// for循环
long start = System.nanoTime();
for (int i = 0; i < array.length; i++) {
    array[i] = i;
}
long forTime = System.nanoTime() - start;

// foreach循环
start = System.nanoTime();
for (int num : array) {
    num = num; // 实际无法修改数组元素!
}
long foreachTime = System.nanoTime() - start;

System.out.println("数组-for: " + forTime + "ns");
System.out.println("数组-foreach: " + foreachTime + "ns");

结果:for循环快约15%(因foreach隐藏了索引访问)

2. 集合遍历测试

在这里插入图片描述

List<Integer> list = new ArrayList<>();
// 填充10_000_000个元素...

// for循环
start = System.nanoTime();
for (int i = 0; i < list.size(); i++) {
    list.get(i);
}
forTime = System.nanoTime() - start;

// foreach循环
start = System.nanoTime();
for (int num : list) {
    // 仅遍历
}
foreachTime = System.nanoTime() - start;

结果:foreach快约30%(因优化了迭代器访问)


五、常见陷阱与解决方案

需要修改集合
遍历时修改?
使用Iterator.remove
新建临时集合
安全删除
collect过滤后替换

1. foreach中修改集合

List<String> list = new ArrayList<>(Arrays.asList("A", "B", "C"));

// 错误示范(抛出ConcurrentModificationException)
for (String s : list) {
    if ("B".equals(s)) {
        list.remove(s); // ❌ 遍历时修改
    }
}

// 正确做法1:使用迭代器
Iterator<String> it = list.iterator();
while (it.hasNext()) {
    if ("B".equals(it.next())) {
        it.remove(); // ✅ 安全删除
    }
}

// 正确做法2:使用for循环
for (int i = 0; i < list.size(); i++) {
    if ("B".equals(list.get(i))) {
        list.remove(i--); // 调整索引
    }
}

2. 基本类型数组问题

int[] nums = {1, 2, 3};
for (int num : nums) {
    num *= 2; // 不影响原数组!
}
System.out.println(Arrays.toString(nums)); // 输出[1, 2, 3]

六、最佳实践指南

  1. 默认选择

    • 集合遍历 → foreach
    • 数组遍历 → 根据是否需要索引选择
  2. 性能关键路径

    • 超大型数组 → 传统for
    • 链表等随机访问慢的集合 → 绝对用foreach
  3. 代码规范

    // 好
    for (Student s : students) { ... }
    
    // 不好(除非需要索引)
    for (int i = 0; i < students.size(); i++) { ... }
    

七、Java8的降维打击

场景传统写法Java8+改进
遍历for(String s : list)list.forEach(System.out::println)
带索引for(int i=0; i<list.size(); i++)IntStream.range(0,list.size()).forEach(i->...)
过滤手动迭代检查list.stream().filter(...).collect(...)
// 更现代的遍历方式
list.forEach(System.out::println);

// 带索引的流式处理
IntStream.range(0, list.size())
    .forEach(i -> System.out.println(i + ": " + list.get(i)));

八、常见陷阱警示牌

«警示»
陷阱
+修改集合异常
+数组元素不可修改
+链表性能灾难
for循环
foreach循环

典型问题

  1. ConcurrentModificationException
  2. 基本类型数组修改无效
  3. LinkedList用for循环get()性能差

九、企业级编码规范建议

  1. 基础规范

    • 集合遍历优先foreach
    • 需要索引时用for
    • 修改集合用Iterator
  2. 性能规范

    // 好:优化数组遍历
    for (int i = 0, len = array.length; i < len; i++)
    
    // 不好:每次计算size()
    for (int i = 0; i < list.size(); i++)
    
  3. 可读性规范

    // 好:明确表达意图
    for (Order order : unpaidOrders) {
        process(order);
    }
    
    // 不好:索引无实际用途
    for (int i = 0; i < orders.size(); i++) {
        process(orders.get(i));
    }
    

十、循环选择终极指南

在这里插入图片描述

结语:循环选择的艺术

🔑 终极选择口诀

foreach简洁又优雅,集合遍历首选它;
for循环更全能,索引控制它最行;
数组遍历看场景,性能关键for能赢;
迭代修改要小心,迭代器方案最安心!

记住:没有最好的循环,只有最合适的场景!

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

码农技术栈

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值