什么时候列表,集合等在Java中抛出java.util.ConcurrentModificationException?

时间:2011-11-19 01:12:05

标签: java

以下代码使用一个简单的列表,并通过foreach循环显示列表中包含的元素,并再次通过while循环显示。

final public class Main
{
    public static void main(String... args)
    {           
        List<String>list=new ArrayList<String>();

        list.add("A");
        list.add("B");
        list.add("C");
        list.add("D");

        for(Object o:list)
        {
            System.out.printf("\n"+o);
        }

        Iterator<String>listIterator=list.iterator();

        //list.add("E");   If uncommented, throws an exception.
        //list.add("F");

        while(listIterator.hasNext())
        {
            System.out.printf("\n"+listIterator.next());
        }
    }
}

当while循环上方注释的两行被取消注释时,它会抛出异常java.util.ConcurrentModificationException。如果这些注释行位于此​​行Iterator<String>listIterator=list.iterator();之上,则效果很好。在处理 EJB 中的实体时,此类异常非常常见。为什么会这样?如何避免?

2 个答案:

答案 0 :(得分:6)

http://download.oracle.com/javase/6/docs/api/java/util/ArrayList.html

  

此类的迭代器和listIterator方法返回的迭代器是快速失败的:如果在创建迭代器之后的任何时候对列表进行结构修改,除了通过迭代器自己的remove或add方法之外,迭代器将抛出一个ConcurrentModificationException。

而不是使用:

Iterator<String>listIterator=list.iterator();

使用:

ListIterator<String> listIterator = list.listIterator();

此迭代器提供了add()方法供您使用。请注意JavaDoc它是如何工作的,因为它可能无法准确提供您所需的内容 - 它不会添加到列表的末尾,而是相对于ListIterator位置的位置。

答案 1 :(得分:1)

每个集合都维护一个名为modCount的变量。此变量记录了修改集合的次数。 在AbstractList

下面找到mdcount的javadoc
/**
* The number of times this list has been <i>structurally modified</i>.
* Structural modifications are those that change the size of the
 * list, or otherwise perturb it in such a fashion that iterations in
 * progress may yield incorrect results.
 *
 * <p>This field is used by the iterator and list iterator implementation
 * returned by the {@code iterator} and {@code listIterator} methods.
 * If the value of this field changes unexpectedly, the iterator (or list
 * iterator) will throw a {@code ConcurrentModificationException} in
 * response to the {@code next}, {@code remove}, {@code previous},
 * {@code set} or {@code add} operations.  This provides
 * <i>fail-fast</i> behavior, rather than non-deterministic behavior in
 * the face of concurrent modification during iteration.
 *
 * <p><b>Use of this field by subclasses is optional.</b> If a subclass
 * wishes to provide fail-fast iterators (and list iterators), then it
 * merely has to increment this field in its {@code add(int, E)} and
 * {@code remove(int)} methods (and any other methods that it overrides
 * that result in structural modifications to the list).  A single call to
 * {@code add(int, E)} or {@code remove(int)} must add no more than
 * one to this field, or the iterators (and list iterators) will throw
 * bogus {@code ConcurrentModificationExceptions}.  If an implementation
 * does not wish to provide fail-fast iterators, this field may be
 * ignored.
 */
protected transient int modCount = 0;

创建迭代器时,会保留modCount的本地副本,并在返回新对象之前对其进行检查。如果发生了更改,则抛出并发修改异常。

可以通过在迭代时不对集合执行任何操作来避免异常。只允许删除,也应该通过迭代器路由,即迭代器#remove