You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

为何增强for循环遍历ArrayList时无法增删元素,普通for循环却可行?

为什么普通for循环修改ArrayList正常,增强for循环会抛ConcurrentModificationException?

核心原因:两种遍历的底层实现逻辑完全不同

  • 普通for循环:直接通过索引调用get(i)访问元素,修改集合时直接调用ArrayList的remove方法。这种方式不会触发ArrayList的**快速失败(fail-fast)**校验——因为整个过程没有用到迭代器,也就不会触发迭代器内部的修改次数校验逻辑。不过你当前的普通循环写法存在隐患:删除元素后,后续元素会自动前移,i++会导致跳过下一个本该遍历的元素。

  • 增强for循环:底层是基于Iterator迭代器实现的。ArrayList的迭代器内部维护了两个关键变量:modCount(集合实际被修改的次数)和expectedModCount(迭代器初始化时记录的预期修改次数),初始时两者数值相等。当你在遍历过程中直接调用ArrayList的remove方法,只会修改modCount,但迭代器的expectedModCount不会同步更新。下一次迭代器执行next()方法时,会检查modCount和expectedModCount是否相等,一旦不等就抛出ConcurrentModificationException——这是fail-fast机制的作用,用来避免集合在遍历过程中被修改导致的数据不一致问题。

安全的遍历修改方式

如果要在遍历中删除元素,推荐两种可靠的写法:

  1. 使用迭代器自带的remove()方法:
private void setupStudentSchedule(){
    Iterator<String> iterator = activeStudent.getCourses().iterator();
    while(iterator.hasNext()){
        String course = iterator.next();
        if(!mainApp.courseMap.containsKey(course)){
            iterator.remove(); // 迭代器的remove方法会同步更新expectedModCount,避免异常
            continue;
        }
    
        try{
            activeStudentSchedule.addCourseToSchedule(mainApp.courseMap.get(course));
        } 
        catch (Exception e){
            System.out.println("problem in setupStudentSchedule()");
            System.out.println(e);
        }
    }
}
  1. 使用Java 8+的removeIf方法(更简洁高效):
private void setupStudentSchedule(){
    ArrayList<String> studentCourses = activeStudent.getCourses();
    // 先批量删除不符合条件的课程
    studentCourses.removeIf(course -> !mainApp.courseMap.containsKey(course));
    // 再遍历剩余课程添加到日程
    for(String course : studentCourses){
        try{
            activeStudentSchedule.addCourseToSchedule(mainApp.courseMap.get(course));
        } 
        catch (Exception e){
            System.out.println("problem in setupStudentSchedule()");
            System.out.println(e);
        }
    }
}

补充:你的普通循环写法的隐患修复

你当前的普通循环在删除元素后用了continue,会导致i++直接执行,跳过被前移的元素。比如集合是[A,B,C,D],删除索引1的B后,集合变成[A,C,D],i变成2,此时访问的是D,漏掉了C。修复这个问题需要在删除后回退索引:

if(!mainApp.courseMap.containsKey(course)){
    activeStudent.getCourses().remove(course);
    i--; // 回退索引,避免跳过前移的元素
    continue;
}

内容的提问来源于stack exchange,提问作者Mio

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.06.27 01:05:11