• java8 Lambda表达式遍历并移除元素,报错:ConcurrentModificationException的解决办法


    1.情景展示

      已知json对象MainExt

      需要把值为空数组的key移除掉,下面是执行代码

      执行结果报错:java.util.ConcurrentModificationException 

    2.原因分析

      大致过程就是:

      符合删除条件--》调用remove()方法后,expectedModCount-1-1,而modCount-1,在进行下次遍历,也就是执行next()方法体里,又去调用了checkForComodification()方法,

      检查modCount和expectedModCount两者的值不一致,所以会抛出ConcurrentModificationException异常。

    3.错误示例

      错误实现一

    Iterator<String> iterator = MainExt.keySet().iterator();
    while(iterator.hasNext()) {
        String key = iterator.next();
        if ("[]".equals(MainExt.get(key).toString())) {
            MainExt.remove(key);
        }
    }
    

      起初,使用迭代器发现还是失败,因为在调用next()方法时,又去调用了remove()方法。

      错误实现二

    JSONObject MainExt2 = new JSONObject(MainExt);
    MainExt2.forEach((k,v) -> {
        if ("[]".equals(v.toString())) {
            MainExt.remove(k);
        }
    });
    

      我们咋一看,已经创建了一个新的对象,并将MainExt的值赋给了MainExt2,但是,通过迭代MainExt2,移除MainExt的子节点,移除失败,

      这才让我意识到,MainExt2并没有和MainExt切断联系,换句话说就是:MainExt2对MainExt的引用,并不是真正意义上的深层拷贝,要想成功,数据完成拷贝后必须切断联系。

    4.正确方式

    String str = "{
    " +
            "                "MedicalType": "门诊",
    " +
            "                "PatientNumber": "202009041167",
    " +
            "                "MedicalDate": "20200904-11:41:31",
    " +
            "                "OrgType": "综合医院",
    " +
            "                "MedicalInsuranceType": [],
    " +
            "                "MedicalInsuranceID": [],
    " +
            "                "Gender": [],
    " +
            "                "FundPayAmount": "0.00",
    " +
            "                "OtherPayAmount": "0.00",
    " +
            "                "AccountPayAmount": "0.00",
    " +
            "                "OwnPayAmount": "0.00",
    " +
            "                "SelfpaymentAmount": "0.00",
    " +
            "                "SelfpaymentCost": "0.00"
    " +
            "            }";
    JSONObject MainExt = JSONObject.parseObject(str);
    // 深拷贝,不拷贝直接移除key的话,会报错:ConcurrentModificationException
    JSONObject MainExt2 = (JSONObject) MainExt.clone();
    MainExt2.forEach((k,v) -> {
        if ("[]".equals(v.toString())) {
            MainExt.remove(k);
        }
    });
    

      通过深层拷贝,复制一份原数据,并与原来对象切断联系,迭代复制后的数据,移除原对象的数据。

      说明:说到底,lambda表达式是无法实现对同一对象遍历的同时,并完成移除子元素的。 

    5.list集合移除节点

    List<String> list = new ArrayList<>();
    list.add("Marydon");
    list.add("18");
    list.add("test");
    

      这里需要注意的是:list集合的大小不能为2,如果是2的话,下面无论是哪一种方式都能正常移除!!!

      错误方式一:for循环

    for (int i = 0; i < list.size(); i++) {
        if ("Marydon".equals(list.get(i))) {
            list.remove(i);
        }
    }
    System.out.println(list);
    

      错误方式二:foreach

    for (String s : list) {
        if ("Marydon".equals(s)) {
            list.remove(s);
        }
    }
    

      错误方式三:通过list移除

    Iterator<String> ite = list.iterator();
    while (ite.hasNext()) {
        String next = ite.next();
        if (next.equals("Marydon")) {
            list.remove(next);
        }
    }
    

      正确方式一:通过迭代器移除

    Iterator<String> ite = list.iterator();
    while (ite.hasNext()) {
        if (ite.next().equals("Marydon")) {
            ite.remove();
        }
    }
    

      20200907

      方式二:removeAll()

    // 存储将要移除的元素        
    List<String> removeList = new ArrayList<>();
    for (String s : list) {
        if (s.equals("Marydon")) {
            removeList.add(s);
        }
    }
    // 移除
    list.removeAll(removeList);
    System.out.println(list);
    

      20200908

      方式三:ArrayList.clone()

    // 复制list
    List<String> newList = (List<String>) ((ArrayList<String>) list).clone();
    // 遍历复制的list
    newList.forEach(e -> {
        if ("Marydon".equals(e)) {
            // 移除原来的list子元素
            list.remove(e);
            // 结束本轮循环(可有可无)
            return;
        }
    });
    
    System.out.println(list);
    

      

    写在最后

      哪位大佬如若发现文章存在纰漏之处或需要补充更多内容,欢迎留言!!!

     相关推荐:

  • 相关阅读:
    c# GDI+简单绘图(二)
    ProE 工程图教程系列4 ProE不能导出dwg等格式的解决办法
    McAfee卸载工具及卡巴KIS2009注册码
    Vista下修改网卡MAC地址
    开机后出现Spooler Subsystem App 的解决办法
    微软office 2007在线编辑平台Office Live Workspace(docx转doc格式)
    美丽的草原风电场————内蒙古锡林浩特阿巴嘎旗风电场
    ProE官方网站系列视频教程
    [转]Stimator:评估您的网站/博客的价值
    关注苏迪曼杯,关注Lining为羽毛球队打造的衣服
  • 原文地址:https://www.cnblogs.com/Marydon20170307/p/13614547.html
Copyright © 2020-2023  润新知