• 使用Iterator对List集合进行增加或者删除操作时报异常的分析


    一、问题

    使用Iterator在对List集合进行遍历集合时,如果只是遍历而不进行增加、删除操作时,可以正常运行吗,但是如果我们在使用迭代器对List集合进行插入或者删除时,就会出现Exception in thread "main" java.util.ConcurrentModificationException这个异常。(调用了next方法)

    代码:
    package com.example.demo.domain;
    
    import java.util.ArrayList;
    import java.util.Iterator;
    import java.util.List;
    
    public class Demo2 {
        public static void main(String[] args) {
    
            List<String> list = new ArrayList<String>() {{
                add("111");
                add("java");
            }};
    
            Iterator<String> iterator = list.iterator();
    
            while (iterator.hasNext()) {
                String next = iterator.next();
                if("java".equals(next)){
                    list.add("666");
                }
            }
    
            System.out.println(list);
        }
    }

    错误:

    Exception in thread "main" java.util.ConcurrentModificationException
        at java.util.ArrayList$Itr.checkForComodification(ArrayList.java:909)
        at java.util.ArrayList$Itr.next(ArrayList.java:859)
        at com.example.demo.domain.Demo2.main(Demo2.java:18)

     由此我们可以知道这个错误时在代码的 18行,也就是下面那行:

    String next = iterator.next();

    二、原因分析

    前提:先了解一个AbstractList中,有一个全局变量madCount

    在AbstractList中,有一个全局变量madCount,记录了结构性改变的次数。结构性改变指的是那些修改了列表大小的操作,在迭代过程中可能会造成错误的结果。madCount交由迭代器(Iterator)和列表迭代器(ListIterator)使用,当进行next()、remove()、previous()、set()、add()等操作时,如果madCount的值意外改变,那么迭代器或者列表迭代器就会抛出ConcurrentModificationException异常。

     

     

     所以我们每次 add 或者 remove 操作时,这个modCount都会自增一次

    获取迭代器是如何操作的?

     

    三、总结

      当我们使用ArrayList做 add 或者 remove 操作时,都会改变 madCount (记录了结构性改变的次数) 的值,而在我们获取迭代器时,其实是获取了ArrayList内部类的迭代器,然后我们使用next()这个方法时都会调用checkForComodification()方法,可以看出在这个方法中抛出了异常,那么抛出异常的条件是因为modCount != expectedModCount这个条件,modCount是指记录了结构性改变的次数,expectedModCount代表期望遍历次数,当我们在使用迭代器进行遍历并插入或者删除时,modCount就会改变,从而导致modCount != expectedModCount,从而抛出异常。

  • 相关阅读:
    cocos2dx3.0戳青蛙游戏(打地鼠)
    深入理解Tomcat系列之五:Context容器和Wrapper容器
    linux下拷贝隐藏文件
    8.8.1 运行计划
    UVALive
    堆排序实现
    C语言中的signal函数
    uboot和内核分区的改动
    Android缩放动画
    .Net 自定义应用程序配置
  • 原文地址:https://www.cnblogs.com/xiejn/p/16322753.html
Copyright © 2020-2023  润新知