Java集合的快速失败原则

上一篇文章讲到怎么删除集合里面的元素,其中提到了快速失败原则。

本章将深入底层源码去分析快速失败原则

public static void main(String[] args) {
    List<String> list = new ArrayList<>();

    list.add("语文");
    list.add("数学");
    list.add("英语");

    System.out.println(list);

    Iterator<String> it = list.iterator();

    while(it.hasNext()) {
        it.remove();
    }

    System.out.println("删除后" + list);
}

以下代码运行结果为:发生IllegalStateException异常,为什么会这样呢?

ArrayList内维护了一个迭代器类Itr,里面定义了一个初始值为-1的lastRet属性保存当前元素的位置,只有调用其next()方法才会获取当前元素,并给lastRet重新赋值,在删除元素时会检测lastRet是否小于0(是否默认值-1),lastRet小于0抛出IllegalStateException异常。如下图(1)(2)(3)

private class Itr implements Iterator<E> {
    int cursor; // 游标,类似于指针、下标
    int lastRet = -1; // (1)关键属性
    int expectedModCount = modCount; (4)

    Itr() {}

    public boolean hasNext() {
        return cursor != size;
    }

    @SuppressWarnings("unchecked")
    public E next() {
        checkForComodification();
        int i = cursor;
        if (i >= size)
            throw new NoSuchElementException();
        Object[] elementData = ArrayList.this.elementData;
        if (i >= elementData.length)
            throw new ConcurrentModificationException();
        cursor = i + 1;
        return (E) elementData[lastRet = i]; // (2)数组下标内给lastRet赋值
    }

    public void remove() {
        // (3)删除前检查lastRet是否小于0,小于0抛出异常,只要调用了next()方法就不会小于0
        if (lastRet < 0)
            throw new IllegalStateException();
        checkForComodification();

        try {
            ArrayList.this.remove(lastRet);
            cursor = lastRet;
            lastRet = -1;
            expectedModCount = modCount; // (5)modCount的值赋给expectedModCount
        } catch (IndexOutOfBoundsException ex) {
            throw new ConcurrentModificationException();
        }
    }

    @Override
    @SuppressWarnings("unchecked")
    public void forEachRemaining(Consumer<? super E> consumer) {
        Objects.requireNonNull(consumer);
        final int size = ArrayList.this.size;
        int i = cursor;
        if (i >= size) {
            return;
        }
        final Object[] elementData = ArrayList.this.elementData;
        if (i >= elementData.length) {
            throw new ConcurrentModificationException();
        }
        while (i != size && modCount == expectedModCount) {
            consumer.accept((E) elementData[i++]);
        }
        cursor = i;
        lastRet = i - 1;
        checkForComodification();
    }

    final void checkForComodification() {
        // (6)检查两个变量的值,若不相等,抛出并发修改异常
        if (modCount != expectedModCount)
            throw new ConcurrentModificationException();
    }
}

当使用迭代器遍历的方式(foreach以及removeIf()方法都是迭代器遍历),但是没有通过迭代器的remove()删除集合元素时,会导致modCount和expectedModCount两个变量的值不相等,程序抛出ConcurrentModificationException异常。如上图(4)(5)(6)

备注:Set和Map快速失败原则同理,这里就不赘述了~

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值