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);