报错:
Exception in thread "main" java.util.ConcurrentModificationExceptionat java.util.ArrayList$Itr.checkForComodification(ArrayList.java:909)at java.util.ArrayList$Itr.next(ArrayList.java:859)at net.micah.Test.main(Test.java:20)
我写的demo:
import java.util.ArrayList;
import java.util.Iterator;
import java.util.List;
import java.util.Objects;public class Test {public static void main(String[] args) {List<String> list = new ArrayList<>();list.add("a");list.add("b");list.add("c");list.add("d");list.add("e");list.add("f");// 隐式创建迭代器 Itr(报错:ConcurrentModificationException) for (String next : list) {System.out.println(next);if (Objects.equals(next, "d")) {list.remove(next);}}System.out.println(list);// fori (无法实时拿到数组index更新,导致index对不上,导致错误的修改)for (int i = 0 ; i < list.size(); i++) {String next = list.get(i);System.out.println(next);if(Objects.equals(next, "d") || Objects.equals(next, "e")) {list.remove(next);}}System.out.println(list);// 显式迭代器(安全可靠)Iterator<String> iterator = list.iterator();while (iterator.hasNext()) {String next = iterator.next();System.out.println(next);if (Objects.equals(next, "d")) {iterator.remove();}}System.out.println(list);}}
迭代器内部是闭环的,校验逻辑为:
final void checkForComodification() {if (modCount != expectedModCount)throw new ConcurrentModificationException();}
expectedModCount 是在创建 Itr(迭代器内部类) 的时候赋值,为那个瞬间的 modCount
private class Itr implements Iterator<E> {int cursor; // index of next element to returnint lastRet = -1; // index of last element returned; -1 if no suchint expectedModCount = modCount;Itr() {}
① 从源代码上说,这个 expectedModCount 只在迭代器的内部方法调用时被修改,而且 modCount + 1 时 expectedModCount 会和 modCount 保持同步。
也就是说,一旦创建了迭代器(包含 foreach 的情况),就只能调用 Itr 给的方法进行 “modify”,不然下次 checkForComodification 检查必定过不了。(modCount + 1 了,但是 expectedModCount 没有变,导致不相等)
② 从设计原则上说,迭代器一旦生成,就对应生成了游标(cursor),对父类变量(ArrayList.this.elementData)进行遍历操作,你要对父类变量进行变更,特别是触动了数据下标的变化,一定要让我来操作,不然我不知道,迭代的后续操作就不正确(安全)了。这就是“对修改封闭”(开闭原则的闭)。
解决方案:
- 用显式迭代器的内部方法进行集合的修改
- 处理成新集合,对新集合进行后续操作
- fori的反向操作(反向可以减少remove对index变化的影响,但是add操作还是会被影响)