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

处理ArrayList循环添加元素时的ConcurrentModificationException问题

解决ArrayList遍历中添加元素导致的ConcurrentModificationException

我完全懂你遇到的麻烦——用增强for循环遍历ArrayList时,一在循环里加新元素就触发ConcurrentModificationException。这个异常其实是Java迭代器的保护机制:当迭代器正在遍历集合时,不允许直接通过集合本身的方法做结构性修改(比如add、remove这类操作),不然迭代器会认为遍历状态已经失效,直接抛出异常。

结合你的Processing代码,我给你几个实用的解决办法:

方案1:用普通for循环(倒序遍历更稳妥)

增强for循环依赖Iterator,而普通for循环直接通过索引访问元素,不会触发迭代器的修改检测。如果你的make()是往集合末尾加元素,倒序遍历还能避免索引混乱的问题:

void draw() {
  background(255);
  // 倒序遍历pipes集合
  for (int i = pipes.size() - 1; i >= 0; i--) {
    Pipe p = pipes.get(i);
    p.display(); // 假设你需要显示Pipe实例
    // 这里可以添加触发生成新Pipe的条件
    if (p.needsNewPipe()) {
      make();
    }
  }
}

要是用正序遍历也可以,但得注意每次加元素后集合size会变大,如果你不想重复处理新添加的元素,倒序是更省心的选择。

方案2:用ListIterator做安全修改

ListIterator是Iterator的子类,支持遍历过程中安全地添加/修改元素,它会同步迭代器和集合的状态,不会抛出异常。你可以把增强for循环换成ListIterator遍历:

void draw() {
  background(255);
  ListIterator<Pipe> iterator = pipes.listIterator();
  while (iterator.hasNext()) {
    Pipe p = iterator.next();
    p.display();
    if (p.needsNewPipe()) {
      // 用ListIterator的add方法直接添加元素
      Pipe newPipe = new Pipe();
      newPipe.create();
      iterator.add(newPipe);
    }
  }
}

这种方式不用改你make()的逻辑,直接在遍历里创建并添加元素就行。

方案3:遍历集合的副本

先创建原集合的副本,遍历副本的同时修改原集合——因为迭代器遍历的是副本,根本不会感知到原集合的修改:

void draw() {
  background(255);
  // 复制pipes集合到新的ArrayList
  ArrayList<Pipe> pipesCopy = new ArrayList<>(pipes);
  for (Pipe p : pipesCopy) {
    p.display();
    if (p.needsNewPipe()) {
      make(); // 直接修改原集合,遍历的是副本,不会触发异常
    }
  }
}

这个方案的好处是代码改动最小,适合快速解决问题,但如果集合很大,复制副本会有一点性能开销。

为什么原代码会出问题?

你用的增强for循环(for (Pipe p : pipes))底层是靠Iterator实现的。当你在遍历过程中调用pipes.add()(也就是make()里的逻辑),集合的结构被修改了,但迭代器不知道这个变化,下次迭代时它会检测到集合的修改次数和迭代器预期的不一致,直接抛出ConcurrentModificationException。

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.05.25 04:18:00