在遍历ArrayList时出现ConcurrentModificationException异常(未删除)

3

我目前遇到一个问题,需要遍历ArrayList。我已经阅读了这里的几篇文章,但似乎没有解决我的问题。以下是我的代码:

//restaurants contains a list of all restaurants and i want to filter them
List<Restaurant> newList = new ArrayList<Restaurant>();
List<Restaurant> allRestaurants = new ArrayList<Restaurant>(restaurants);
if (query != null && query.length() > 0 && !query.equals("*")) {
            synchronized (allRestaurants) {
                for (Iterator<Restaurant> it = allRestaurants.iterator(); it
                        .hasNext();) {
                    Restaurant restaurant = it.next();
                    if (restaurant.getCity().contains(query)) {
                        synchronized (newList) {
                            newList.add(restaurant);
                        }
                    } else {
                        newList = allRestaurants;
                    }
                }
            }

这段代码是我根据在这里读到的几个想法进行修改的(使用同步锁,使用迭代器而不是for-each循环)。我甚至已经对整个方法进行了同步,但仍然遇到了异常。

异常发生在以下行:

Restaurant restaurant = it.next();

我不理解这个问题。在这行代码中,我没有对列表进行任何操作。为什么会出现这种情况,我该如何解决?


1
你可能不想要一个嵌套的同步块。 - John Kane
5个回答

3
else{
    newList = allRestaurants;
}

那几乎肯定是您的问题。
将 newLlist 分配给 allRestaurants,然后添加到 newList 中会导致您的并发修改异常。
这是在 newList = allRestaurants 之后,任何对 newList 的添加都会更新 allRestaurants 中的 mod 计数,从而引发错误。

你是对的,我也在那里找到了它。它应该属于外部 if 语句。 - MrHill
如何避免这个异常?Set<String> keys = obj.keySet(); for (String key : keys) {} - Coding world

0

在循环内部不能更改用于迭代的ArrayList;这就是ConcurrentModificationException所表示的(http://docs.oracle.com/javase/1.4.2/docs/api/java/util/ConcurrentModificationException.html),而newList = allRestaurants;加上newList.add(restaurant);可能会更改列表allRestaurants

因此,你可以做的是:

  1. 创建另一个列表
  2. 将要修改的项目放入该列表中
  3. 在循环之后将新列表(addAllremoveAll)添加/删除到旧列表中

欲知详情,请访问http://www.javacodegeeks.com/2011/05/avoid-concurrentmodificationexception.html


0

在else分支中

else {
   newList = allRestaurants;
}

你将newList设置为allRestaurants。接下来的修改newList.add(restaurant);会改变allRestaurants列表。

当调用it.next()时,会抛出异常,因为迭代器会检查其源是否已更改。


0

失败始于:

newList = allRestaurants;

这将两个引用都指向同一个列表(即您正在迭代的列表)。然后,您执行以下操作:

newList.add(restaurant);

修改列表。从ConcurrentModificationException的javadoc中:

请注意,此异常并不总是表示对象已被不同线程同时修改。如果单个线程发出违反对象合同的方法调用序列,则对象可能会抛出此异常。例如,如果线程在使用快速失败的迭代器迭代集合时直接修改集合,则迭代器将抛出此异常。


0

你的问题在else语句中。

         newList = allRestaurants;

这就是为什么你会得到异常的原因


网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接