图片来源:https://blog.csdn.net/csp277/article/details/46462605

Collection继承了Iterable接口
关于集合遍历时增删元素:
这样可以
Iterator<String> iterator=list.iterator();
while(iterator.hasNext())
{
if(iterator.next().equals("bbb"))
{
iterator.remove();
}
}
普通for循环也可以
for(int i=0;i<list.size();i++)
{
if(list.get(i).equals("bbb"))
{
list.remove(i);
}
}
但是增强for循环是不可以的
for(String str:list)
{
if(str.equals("bbb"))
{
list.remove(str);
}
}
会抛出java.util.ConcurrentModificationException异常
利用迭代器进行迭代时,直接用list删除元素也是不可以的
Iterator<String> iterator=list.iterator();
while(iterator.hasNext())
{
String next=iterator.next();
if(next.equals("bbb"))
{
list.remove(next);
}
}
会抛出java.util.ConcurrentModificationException异常

看异常的日志,是在调用next()方法的时候才抛出的,并非调用list.remove()的时候
为什么抛出了异常,看下ArrayList中的代码:


在next()方法的第一句就做了判断
我们调用list.iterator()的时候会初始化Itr
public Iterator<E> iterator() {
return new Itr();
}

初始化时便会对expectedModCount进行赋值,既然next()方法中抛出了异常,说明两个值不等了,那必然是list.remove()方法对modCount进行了修改,看下list.remove()方法

modCount的值修改了,但是Itr的成员变量expectedModCount的值并没有发生变化,所以这儿抛出了异常。
那么java为什么要这么设计呢,如果不抛出这个异常,继续让程序往下面走,会发生什么情况?
利用迭代器在遍历集合的过程中是利用cursor这个变量控制的
int cursor; // index of next element to return
在迭代过程中会利用it.hasNext()来判断是否还有下一个元素
protected int limit = ArrayList.this.size;
int cursor; // index of next element to return
int lastRet = -1; // index of last element returned; -1 if no such
int expectedModCount = modCount;
public boolean hasNext() {
return cursor < limit;
}
其实这个操作并没有什么影响,这儿是可以正确拿到集合的大小的,但是你会发现在next()遍历中会存在跳过元素的情况

假设遍历到集合的第二个元素时,删除了第二个元素,但是此时cursor是等于2

再调用next的时候原先的第三个元素变为了第二个元素,cursor没有做任何操作,值为2,此时就跳过了第二个元素,直接遍历第三个元素了,这就不正常了。
那么调用iterator.remove()方法为什么可以呢?

因为在这个方法中会同步更新cursor值
网友评论