Java集合一般调用删除方法都是集合的方法,例如:
List list = new ArrayList();
list.add(...);
list.remove(...);
但是,如果在循环的过程中调用集合的remove()方法,一般就会导致循环出错,例如:
for(int i=0;i<list.size();i++){
list.remove(...);
}
循环过程中list.size()的大小变化了,就导致了错误。这时会抛出异常ConcurrentModificationException().
所以,如果你想在循环语句中删除集合中的某个元素,就要用迭代器iterator的remove()方法,因为它的remove()方法不仅会删除元素,还会维护一个标志,用来记录目前是不是可删除状态.
今天发现一个现象。
List <String> list=new ArrayList<String>();
list.add("11");
list.add("22");
list.add("33");
for(Iterator iter=list.iterator();iter.hasNext();){
//迭代器循环过程中,调用迭代器的remove方法。不能直接调用list的remove
String st=(String)iter.next();
if(st.equals("22")){
list.remove(st);//List的remove方法
// iter.remove();//Iterator的remove方法
}
}
正常情况下,我们会调用Iterator的remove方法,但是我进行了个尝试,这段代码你用list的remove()方法d.remove(st),当st为11,33时都会抛异常,但是当它为22时,不会抛异常.非常不解。接着试了几次后发现,在一个list中,只有删除倒数第二个元素时是正常的,删除其它位置都会有异常抛出。于是我翻看了AbstractList中的迭代实现.
/**
* The modCount value that the iterator believes that the backing
* List should have. If this expectation is violated, the iterator
* has detected concurrent modification.
*/
int expectedModCount = modCount;
public boolean hasNext() {
return cursor != size();
}
public E next() {
checkForComodification();
try {
E next = get(cursor);
lastRet = cursor++;
return next;
} catch (IndexOutOfBoundsException e) {
checkForComodification();
throw new NoSuchElementException();
}
}
public void remove() {
if (lastRet == -1)
throw new IllegalStateException();
checkForComodification();
try {
AbstractList.this.remove(lastRet);
if (lastRet < cursor)
cursor--;
lastRet = -1;
expectedModCount = modCount;
} catch (IndexOutOfBoundsException e) {
throw new ConcurrentModificationException();
}
}
final void checkForComodification() {
if (modCount != expectedModCount)
throw new ConcurrentModificationException();
}
}
cursor标示着当前list的索引,不断地与list size比对。如果hasNext返回true,会紧接着执行next方法,在next方法中检查当前list有没有被修改过。
在list迭代过程中,如果删除一个元素,那么size就减一,hasNext提前结束,迭代不会到达list的最后一个元素。也就是说,如果在迭代到list倒数第二个元素时删除此元素,接下来的hasNext会返回false,迭代结束,不会进入next方法中做检查,也就不会出什么问题。而除此之外的其它情况下,hasNext都是true,接下来的next方法检查时会产生异常。