以下代码使用一个简单的列表,并通过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 中的实体时,此类异常非常常见。为什么会这样?如何避免?
答案 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