• 禁止foreach循环使用remove/add----快速失败


    阿里巴巴开发手册中有一条:

    7【强制】不要在 foreach 循环里进行元素的 remove / add 操作。 remove 元素请使用 Iterator
    方式,如果并发操作,需要对 Iterator 对象加锁。
    正例:
    Iterator<String> iterator = list.iterator();
    while (iterator.hasNext()) {
      String item = iterator.next();
      if (删除元素的条件) {
        iterator.remove();
      }
    }
    反例:
    List<String> list = new ArrayList<String>();
    list.add("1");
    list.add("2");
    for (String item : list) {
      if ("1".equals(item)) {
        list.remove(item);
      }
    }
    说明:以上代码的执行结果肯定会出乎大家的意料,那么试一下把“1”换成“2”,会是同样的
    结果吗?

    代码重现:

    public static void main(String[] args) {
            List<String> list = Lists.newArrayList("a","b","c","d");
            for (String userName : list) {
                if (userName.equals("a")) {
                    list.remove(userName);
                    list.add(userName);
                }
            }
    
        }

    结果:

    Exception in thread "main" java.util.ConcurrentModificationException
    at java.util.ArrayList$Itr.checkForComodification(ArrayList.java:901)
    at java.util.ArrayList$Itr.next(ArrayList.java:851)
    at com.it.test.TestUnit.main(TestUnit.java:23)

    异常:

    /*
    *
    modCount:实际修改次数
    *expectedModCount:期望修改次数
    */
    final
    void checkForComodification() { if (modCount != expectedModCount) throw new ConcurrentModificationException(); }

    这个就是就是快速失败机制——fail-fast

    原因:

      出现这个异常的原因,是因为foreach循环中,通过iterator修改了集合,但是元素的add/remove却是直接使用的集合类自己的方法。通过反编译得知,foreach通过while和Iterator实现的。

    这就导致iterator在遍历的时候,会发现有一个元素在自己不知不觉的情况下就被删除/添加了,就会抛出一个异常,用来提示用户,可能发生了并发修改。


    解决:

      1、使用普通for循环进行操作,因为普通for循环并没有用到Iterator的遍历,所以压根就没有进行fail-fast的检验。

      2、直接使用Iterator进行操作

      3、使用Java 8中提供的filter过滤

      4、直接使用fail-safe的集合类

      5、使用增强for循环其实也可以

      以上这五种方式都可以避免触发fail-fast机制,避免抛出异常。如果是并发场景,建议使用concurrent包中的容器,如果是单线程场景,Java8之前的代码中,

    建议使用Iterator进行元素删除,Java8及更新的版本中,可以考虑使用Stream及filter。

    原文地址:https://mp.weixin.qq.com/s/e9ITxUmsMFhfjeHhOgTtfA

  • 相关阅读:
    html5实现全屏的api方法
    用html5(requestFullscreen) js实现点击一个按钮使浏览器全屏效果
    HTML5 中fullscreen 中的几个API和fullscreen欺骗
    杭州收集
    JS DOM -- 关于回车键盘事件执行事件
    AngularCSS 的引入: CSS On-Demand for AngularJS
    用Javascript获取页面元素的位置
    angularjs 可以加入html标签方法------ng-bind-html的用法总结(2)
    angularjs 可以加入html标签方法------ng-bind-html的用法总结(1)
    onkeypress、onkeydown、onkeyup
  • 原文地址:https://www.cnblogs.com/huigelaile/p/10857407.html
Copyright © 2020-2023  润新知