使用普通for循环时删除元素
验证代码:
List<String> list = new ArrayList<>();
list.add("1");
list.add("2");
list.add("3");
for (int i = 0; i < list.size(); i++) {
System.out.println(list.get(i));
list.remove(i);
}
// 只会打印出1,3,会漏掉2
此时删除元素,会导致元素前移,当i为1时,实际上访问的时原数组下标为2的数据,而原数组中下标为1的,此时已经前移到下标0处,所以不能在使用普通for循环时删除元素
使用增强for循环时删除元素
原始代码:
List<String> list = new ArrayList<>();
list.add("1");
list.add("2");
list.add("3");
for (String s : list) {
list.remove(s);
}
增强for循环在编译后会被优化为迭代器
反编译代码:
List<String> list = new ArrayList();
list.add("1");
list.add("2");
list.add("3");
Iterator var4 = list.iterator();
while(var4.hasNext()) {
String s = (String)var4.next();
list.remove(s);
}
而迭代器在每次使用next方法获取下一个元素时,会检查内部的modCount变量与expectedModCount变量是否一致,而List的remove方法在移除元素时,不会更新迭代器中的expectedModCount变量,只更新了全局的modCount,导致在next时实际值与期望值不符。
ArrayList的remove源码:
迭代器的next源码(红线标注的地方则为检查modCount值的方法):
]
使用迭代器时删除元素
验证代码:
List<String> list = new ArrayList();
list.add("1");
list.add("2");
list.add("3");
Iterator iterator = list.iterator();
while(iterator.hasNext()) {
String next = (String)iterator.next();
iterator.remove();
}
迭代器删除时,必须先调用next方法,然后在调用remove方法
原因: 在remove时使用lastRet下标变量去删除数组元素的,而初始化时默认的时-1且每次删除后都会置为-1,如果不调用next方法将当前元素的下标赋予lastRet,则remove时,会直接抛出非法状态异常
迭代器remove方法:
红线1的位置调用ArrayList的remove方法移除元素,此时修改了modCount,
红线2的位置将modCount值同步到了expectedModCount变量
并在1,2之间的代码更新了下一次下标的位置
同步后在下一次next时,检查modCount就不会抛出ConcurrentModificationExecption异常