下面的代码使用一个简单的列表,并通过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 中的实体时,这种异常非常常见。为什么会发生这种情况?怎样才能避免呢?
http://download.oracle.com/javase/6/docs/api/java/util/ArrayList.html
由该类的iterator和listtiterator方法返回的迭代器是快速失败的:如果在迭代器创建后的任何时间,以除通过迭代器自己的remove或add方法之外的任何方式修改列表,迭代器将抛出ConcurrentModificationException。
而不是使用:
Iterator<String>listIterator=list.iterator();
使用:
ListIterator<String> listIterator = list.listIterator();
这个迭代器提供了一个add()
方法供您使用。注意在JavaDoc中它是如何工作的,尽管它可能没有提供您所需要的-它不会添加到列表的末尾,而是添加相对于ListIterator
位置的位置。
每个集合维护一个名为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的本地副本,并在返回新对象之前进行检查。如果发生了更改,则抛出并发修改异常。
可以通过在迭代集合时不对其进行任何操作来避免异常。只允许删除,并且应该通过迭代器路由,即iterator #remove