• 阿里开发手册之ArrayList正确操作方式


    [强制]不要在foreach循环里进行元素的remove/add操作。remove 元索请使用 Iterator方式,如果并发操作,需要对Iterator对象加锁。​

    正例:
        ist<String> list = new ArrayList<>0;
        list,add("1);
        listadd(C2";
        Iterator<String> iterator = listiterator0);
        while (iterator. hasNext0) I
              String item = iterator.next0;
              if (删除元素的条件) {
                  iterator.remove0;
             }
        }
    反例:
        for (String item : list) 1
             if (C1'equals(tem) (
                 listremovelitem);
             }
        }
     

    说明:以上代码的执行结果肯定会出乎大家的意料,那么试一下把"1"换成*2”, 会是同样的结果吗?

     

    运行结果如下

    看似没有语法错误,那报错的原因是什么?该怎么改呢?

    首先咱们把当前代码编译后的字节码文件反编译看看

    可以看到上面我们写的foreach被转成了迭代器,在24行删除的时候是用的ArrayList的remove方法。接下来再看ArrayList源码,在看源码前要了解一个知识点,ArrayList是继承了AbstractList。

    在AbstractList中有一个变量modCount

    这个变量的作用是统计ArrayList操作的次数,比如添加删除都会加一的。接下来再看ArrayList中的remove方法

    在这里当要删除的元素在数组中找到了以后,就调用fastRemove方法,接下来再看看fastRemove方法

    在这里可以看到对于modCount进行了++操作。再回过头来看我们写代码的反编译代码

    执行了ArrayList中的remove方法,所以会执行++this.modCount;

    执行完remove(var3)以后会再执行hashNext和执行(String)var2.next();那咱们再看看迭代器及他的next方法

    在迭代器中有一个expectedModCount;代表对 ArrayList 修改次数的期望值,把ArrayList中的modCount赋值给了他,证明初始值就是ArrayList中的modCount。

    然后在执行next方法的时候会首先调用checkForComodification方法,如上图660行,咱们再来看checkForComodification方法

    在这里判断了ArrayList中的操作次数modCount和期望操作次数。问题其实就在这里,当我们调用了remove以后modCount就会执行++,加一操作,但是expectedModCount还是最开始获取迭代器的时候把之前的modCount赋值给expectedModCount的,所以这个时候两个数是不相等的,会抛出异常ConcurrentModificationException。如何规避这个问题呢,可以用迭代器中的remove方法,看迭代器中的remove源码

    在迭代器中的每次删除数据的时候都会把modCount赋值给expectedModCount,这样在判断的时候就肯定是相等的了。如下图

    如有不详的地方,欢迎评论区讨论

     

     

    有完整的Java初级,高级对应的学习路线和资料!专注于java开发。分享java基础、原理性知识、JavaWeb实战、spring全家桶、设计模式、分布式及面试资料、开源项目,助力开发者成长!


    欢迎关注微信公众号:码邦主

     

  • 相关阅读:
    误报的java.sql.SQLException: Parameter number 21 is not an OUT parameter
    mysql bin-log和innodb_log的关系
    线上mysql内存持续增长直至内存溢出被killed分析(已解决)
    mysql服务器io等待高定位与分析
    mysql 5.6到percona 5.6小版本升级
    mysql内存消耗分析
    centos 7安装mysql报错-bash: ./scripts/mysql_install_db: /usr/bin/perl: bad interpreter: No such file or directory
    windows 7文件误删shift+delete后找回
    oschina github使用指南
    couchbase单向同步
  • 原文地址:https://www.cnblogs.com/hehe199316/p/14073645.html
Copyright © 2020-2023  润新知