for循环,会导致List中的元素的下标变动
public static void main(String[] args) {
List<Integer> list = new ArrayList<Integer>();
list.add(1);
list.add(2);
list.add(3);
list.add(4);
list.add(5);
list.add(6);
// i < 5 是为了不发生空之争一场
for (int i = 0; i < 5; i++) {
System.out.println(list.get(i));
if (list.get(i) == 1) {
list.remove(i);
}
}
}
// 输出
// 1
// 3
// 4
// 5
// 6
从输出可以看到list.remove(0)
之后,2
并没有输出,因为删除元素导致了index 0
之后的元素集体前移了
增强for循环
public static void main(String[] args) {
List<String> list = new ArrayList<>();
list.add("a");
list.add("b");
list.add("c");
for (String i : list) {
if (i.equals("a")) {
list.remove(i);
}
System.out.println(i);
}
}
输出:
// 输出
a
Exception in thread "main" java.util.ConcurrentModificationException
at java.base/java.util.ArrayList$Itr.checkForComodification(ArrayList.java:1042)
at java.base/java.util.ArrayList$Itr.next(ArrayList.java:996)
可以看到,抛出了异常,但是a
被打印出来了,所以是下次循环出了问题。可以看出增强for循环
其实就是使用了迭代器。
定位到报错的位置:
final void checkForComodification() {
if (modCount != expectedModCount)
throw new ConcurrentModificationException();
}
其中,modCount
代表list
被修改的次数,expectedModCount
表示这个迭代器期望该集合被修改的次数。其值是在ArrayList.iterator
方法被调用的时候初始化的。
再看remove(Object o)方法的操作
:
public boolean remove(Object o) {
final Object[] es = elementData;
final int size = this.size;
int i = 0;
found: {
if (o == null) {
for (; i < size; i++)
if (es[i] == null)
break found;
} else {
for (; i < size; i++)
if (o.equals(es[i]))
break found;
}
return false;
}
fastRemove(es, i);
return true;
}
private void fastRemove(Object[] es, int i) {
modCount++;
final int newSize;
if ((newSize = size - 1) > i)
System.arraycopy(es, i + 1, es, i, newSize - i);
es[size = newSize] = null;
}
可以看到,只修改了modCount
,没有修改expectedModCount
,所以在调用next()
方法,就会抛出了异常