为何增强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机制的作用,用来避免集合在遍历过程中被修改导致的数据不一致问题。
安全的遍历修改方式
如果要在遍历中删除元素,推荐两种可靠的写法:
- 使用迭代器自带的
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); } } }
- 使用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
相关产品推荐
相关产品推荐

