Wondercease

浙ICP备2022017321号

集合foreach删除元素问题

例子

for(Integer integer:list){

System.out.println(integer);

if(integer.equals(0)){

list.remove(integer);

}

}

会报错

for(Integer integer:list){

System.out.println(integer);

if(integer.equals(3)){

list.remove(integer);

}

}

[0, 1, 2, 4]

代码根本上没有什么区别,只是在删除的条件判断不太一样,那到底为什么会出现这样问题呢?

foreach 循环实际上是用的 iterator 迭代器迭代

源码

private class Itr implements Iterator<E>{

intcursor;// index of next element to return

intlastRet=-1;// index of last element returned; -1 if no such

intexpectedModCount=modCount;

// prevent creating a synthetic constructor

Itr(){}

public booleanhasNext(){

returncursor!=size;

}

@SuppressWarnings(“unchecked”)

public Enext(){

checkForComodification();

含义

modCount— 在父类AbstractList中初始化为0,表示集合修改次数的期望值

cursor –迭代器的游标,元素的索引值,初始值为0

lastRet –返回最后一个元素的索引值、如果没有找到则返回-1

expectedModCount –修改次数的期望值,可以看到在迭代器初始化时,这个属性就被赋值为当前修改次数的值了。

checkForComodification –此方法用来检查修改次数是否发生变化,从而判断是否需要触发异常。

在迭代过程中,每一次迭代,cursor会+1, 而hasNext()会判断是否存在下一个元素、next()获取下一个元素的值,最终直到不存在下一个元素,则迭代结束。

看到报错的原因在于进入next中的 checkForComodification()报错了即:

ArrayList.this.modCount != this.expectedModCount

具体的原因是:如果你在遍历过程中删除元素,集合中modCount就会变化,但是迭代器中的expectedModCount没有改变所以报错了。

我们怎样来删除元素呢?—-可以使用迭代器里面的remove()方法

public void remove(){

if(lastRet<0)

throw newIllegalStateException();

checkForComodification();

try{

ArrayList.this.remove(lastRet);

cursor=lastRet;

lastRet=-1;

expectedModCount=modCount;// 处理expectedModCount

}catch(IndexOutOfBoundsException ex){

throw newConcurrentModificationException();

}

可以看见的 expectedModCount = modCount;也同时被修改

iterator.remove();

发表评论

您的电子邮箱地址不会被公开。