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 = "{\n" + " \"MedicalType\": \"門診\",\n" + " \"PatientNumber\": \"202009041167\",\n" + " \"MedicalDate\": \"20200904-11:41:31\",\n" + " \"OrgType\": \"綜合醫院\",\n" + " \"MedicalInsuranceType\": [],\n" + " \"MedicalInsuranceID\": [],\n" + " \"Gender\": [],\n" + " \"FundPayAmount\": \"0.00\",\n" + " \"OtherPayAmount\": \"0.00\",\n" + " \"AccountPayAmount\": \"0.00\",\n" + " \"OwnPayAmount\": \"0.00\",\n" + " \"SelfpaymentAmount\": \"0.00\",\n" + " \"SelfpaymentCost\": \"0.00\"\n" + " }"; 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);