我有一个数组列表,我想对它进行迭代。在迭代它时,我必须同时删除元素。显然,这会抛出一个java.util.ConcurrentModificationException。

处理这个问题的最佳实践是什么?我应该先克隆列表吗?

我删除的元素不是循环本身,而是代码的另一部分。

我的代码是这样的:

public class Test() {
    private ArrayList<A> abc = new ArrayList<A>();

    public void doStuff() {
        for (A a : abc) 
        a.doSomething();
    }

    public void removeA(A a) {
        abc.remove(a);
    }
}

a.doSomething可能调用Test.removeA();


当前回答

for (A a : new ArrayList<>(abc)) {
    a.doSomething();
    abc.remove(a);
}

其他回答

“我应该先克隆列表吗?”

这将是最简单的解决方案,从克隆中删除,并在删除后将克隆复制回来。

以我的rummikub游戏为例:

SuppressWarnings("unchecked")
public void removeStones() {
  ArrayList<Stone> clone = (ArrayList<Stone>) stones.clone();
  // remove the stones moved to the table
  for (Stone stone : stones) {
      if (stone.isOnTable()) {
         clone.remove(stone);
      }
  }
  stones = (ArrayList<Stone>) clone.clone();
  sortStones();
}

你试图在高级的“for循环”中从列表中删除值,这是不可能的,即使你应用了任何技巧(你在你的代码中做了)。 更好的方法是编写迭代器级别的代码。

我想知道为什么人们没有建议传统的for循环方法。

for( int i = 0; i < lStringList.size(); i++ )
{
    String lValue = lStringList.get( i );
    if(lValue.equals("_Not_Required"))
    {
         lStringList.remove(lValue);
         i--; 
    }  
}

这也同样有效。

使用普通的For循环而不是For循环。例如,下面的代码删除了数组列表中的所有元素,而没有给出java.util.ConcurrentModificationException。您可以根据您的用例修改循环中的条件。

for(int i=0; i<abc.size(); i++)  {
       e.remove(i);
 }

从数组列表的JavaDocs

该类的迭代器和listIterator返回的迭代器 方法是快速失败的:如果列表在任何地方被结构修改 方法创建迭代器后的任何时间 迭代器自己的remove或add方法时,迭代器将抛出 并发修改异常

如果你的目标是从列表中删除所有元素,你可以遍历每一项,然后调用:

list.clear()