fail-fast机制

fail-fast机制

fail-fast(快速失败)机制在Java集合中都存在,本文就ArrayList分析。

fail-fast是什么?

先从ArrayList的官方解释看看:

/**
 * The iterators returned by this class's {@link #iterator() iterator} and
 * {@link #listIterator(int) listIterator} methods are <em>fail-fast</em>:</a>
 * if the list is structurally modified at any time after the iterator is
 * created, in any way except through the iterator's own
 * {@link ListIterator#remove() remove} or
 * {@link ListIterator#add(Object) add} methods, the iterator will throw a
 * {@link ConcurrentModificationException}.  Thus, in the face of
 * concurrent modification, the iterator fails quickly and cleanly, rather
 * than risking arbitrary, non-deterministic behavior at an undetermined
 * time in the future.
 *
 * <p>Note that the fail-fast behavior of an iterator cannot be guaranteed
 * as it is, generally speaking, impossible to make any hard guarantees in the
 * presence of unsynchronized concurrent modification.  Fail-fast iterators
 * throw {@code ConcurrentModificationException} on a best-effort basis.
 * Therefore, it would be wrong to write a program that depended on this
 * exception for its correctness:  <i>the fail-fast behavior of iterators
 * should be used only to detect bugs.</i>
 *
 */

翻译:
在迭代器创建之后,集合有机构性修改,除非使用迭代器自身的addremove动作,使用ArrayList上的方法对集合中数据进行任何操作
(包括查询和修改),
都会触发快速失败机制,表现为抛出ConcurrentModificationExeception 异常…
迭代器的快速失败并不能保证,即存在有错误发生也没触发的情况,所以,不该依赖这个依赖异常来写程序,仅是用来检查程序是否有bug

通俗的个人理解:

快速失败机制,对于集合上的操作,比如查询,修改,若数据出现不确定的情况,便不再返回一个不确定的结果,而是直接抛出异常,让用户尽快
知道有错误发生了。符合程序的确定性的原则。

例子:

遍历过程中使用ArrayList的方法删除元素,在下一次调用迭代器的next()方法时,抛出异常

        //初始一个集合并设置数据
        ArrayList<String> list = new ArrayList<>();
        for (int i = 0; i < 4; i++) {
            list.add(i+"");
        }

        //形式1:增强型For遍历
        for ( String e :list) { //以增强For来遍历集合时,会调用集合内部的迭代器
            if (e.equals("1")) {    //遍历过程中使用ArrayList的方法删除元素,在下一次调用迭代器的next()方法时,抛出异常
                list.remove(e);
            }
            System.out.println(e);
        }

Java中,若是使用增强型For,遍历集合类时,本质使用其内部的迭代器来遍历

        //形式2:增强型For的本质形式(去语法糖)
        ListIterator<String> lit = list.listIterator();
        while (lit.hasNext()) {
            String e = lit.next();
            if (e.equals("1")) {
                list.remove(e);   //使用ArrayList的remove方法
            }
            System.out.println(e);
        }

正确用法

        //形式3,使用自身的迭代器删除,不会抛出异常
        ListIterator<String> lit = list.listIterator();
        while (lit.hasNext()) {
            String e = lit.next();
            if (e.equals("1")) {
                lit.remove();   //调用迭代器自身的remove方法,
            }
            System.out.println(e);
        }

内部实现原理:

List类中有一个变量modCount,记录当前集合结构性修改的次数,(比如增加元素,删除元素都会导致结构性修改),初始为0,在add(),
remove()方法中都会调用modCount++
迭代器Iterator中有一个变量expectedModCount,用于跟踪List中的modCount的值,正常情况下,这两个值是保持相等的,这样可保证
迭代器能够正确无误的遍历所有的元素。若是List自己的删除一个元素,ModCount加1,而迭代器中的ExpectedModCount并没有做修改,
迭代器调用next()方法时,检查到两个值不相同,即抛出异常,表示迭代器已经无法保证正确遍历元素了。
若想要遍历中删除,就要使用该迭代器
自身的remove方法,该方法会修改expectedModCountmodCount相等。

  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值