Java在使用迭代器遍历集合的时候不能删除集合元素否则就会抛出异常,而在删除倒数第二个元素时却不会有异常。 且最后一个元素不会被遍历。
forEach:
该循环会根据循环的对象来创建一个iterator迭代对象,可用这个迭代对象来表示遍历一个集合,每次forEach操作时都会先执行iterator.hasnext(); // 判断是否有下个元素,再执行obj = iterator.next() // 下个元素是什么,赋值给obj
报错位置的源码:
public boolean hasNext() {
return this.cursor != ArrayList.this.size;
}
public E next() {
this.checkForComodification();
int i = this.cursor;
if (i >= ArrayList.this.size) {
throw new NoSuchElementException();
} else {
Object[] elementData = ArrayList.this.elementData;
if (i >= elementData.length) {
throw new ConcurrentModificationException();
} else {
this.cursor = i + 1;
return elementData[this.lastRet = i];
}
}
}
final void checkForComodification() {
if (ArrayList.this.modCount != this.expectedModCount) {
throw new ConcurrentModificationException();
}
}
在第22行为报错的原因:ArrayList.this.modCount != this.expectedModCount
以foreach方式遍历元素的时候,会生成iterator,然后使用iterator遍历。在生成iterator的时候,会保存一个expectedModCount参数,这个是生成iterator的时候期望集合中修改元素的次数。如果你在遍历过程中删除元素,那么MondCount就会发生变化。
modCount是指这个list对象从new出来到现在被修改次数,当调用List的add或者remove方法的时候,这个modCount都会自动增减;
expectedModCount是指Iterator现在期望这个list被修改的次数是多少次。
iterator创建的时候modCount被赋值给了expectedModCount,但是调用list的add和remove方法的时候不会同时自动增减expectedModCount,这样就导致两个count不相等,从而抛出异常。
解决方法
如果想让其不抛出异常,一个办法是让iterator在调用hasNext()方法的时候返回false,这样就不会进到next()方法里了。这里cursor是指当前遍历时下一个元素的索引号。比如删除倒数第二个元素的时候,cursor指向最后一个元素的,而此时删掉了倒数第二个元素后,cursor和size()正好相等了,所以hasNext()返回false,遍历结束,这样就成功的删除了倒数第二个元素了。