深入理解ArrayList iterator remove

我们都知道在list遍历中使用ArrayList.remove 是不安全的。会直接抛出运行时异常java.util.ConcurrentModificationException

具体是为什么呢?

通俗的来讲是因为list列表里面发生了index偏差,当你remove了一个元素,会影响整个list的长度,并且在获取下一元素的时候发生错误。
所以我们要用iterator.next获取下个节点

看下底层方法

我们定位到ArrayList.class中(ArrayList继承List,List继承Collection)
在List.class中,我们可以看到iterator()、get()、add()等抽象方法,并在ArrayList中,对这些抽象方法进行重写。

在ArrayList中有两个关键的参数modCount、expectedModCount,我称为运算计数,可以保证数据准确性
每次调用add,remove,clear,modCount都会自增+1,expectedModCount则为期待的运算计数。

当我们用遍历列表,foreach、iterator都会更新赋值 modCount =expectedModCount。

Itr() {
this.expectedModCount = ArrayList.this.modCount;
}

如果遍历list列表的期间,用了list.remove(),modCount++会自增,然鹅expectedModCount却没有更新。

if (this.modCount != expectedModCount) {
throw new ConcurrentModificationException();
}

抛出异常ConcurrentModificationException。

//iterator的remove
public void remove() {
if (this.lastRet < 0) {
throw new IllegalStateException();
} else {
this.checkForComodification();

try {
ArrayList.this.remove(this.lastRet);
this.cursor = this.lastRet;
this.lastRet = -1;
this.expectedModCount = ArrayList.this.modCount;
} catch (IndexOutOfBoundsException var2) {
throw new ConcurrentModificationException();
}
}
}
//普通的remove
private void fastRemove(Object[] es, int i) {
++this.modCount;
int newSize;
if ((newSize = this.size - 1) > i) {
System.arraycopy(es, i + 1, es, i, newSize - i);
}

es[this.size = newSize] = null;
}

但是如果用Iterator的remove里面,不仅会自增自己的modCount,还会更新expectedModCount,
校验数据正确性时expectedModCount = modCount ,保证了数据的正确性

最后附上正确的remove方法

List<Integer> arrayList = new ArrayList<>();
for (int i = 0; i < 20; i++) {
    arrayList.add(Integer.valueOf(i));
}

// 复现方法一
Iterator<Integer> iterator = arrayList.iterator();
while (iterator.hasNext()) {
    Integer integer = iterator.next();
    if (integer.intValue() == 5) {
    //arrayList.remove(integer);
    iterator.remove();
}
}
System.out.println(arrayList.toString());
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值