ArrayList
2020-05-17 本文已影响0人
森林中大鸟
ArrayList foreach删除元素报错分析
List<String> a = new ArrayList<String>();
a.add("1");
a.add("2");
for (String temp : a) {
if("1".equals(temp)){
a.remove(temp);
}
}
以上代码对应class文件如下:
List a = new ArrayList();
a.add("1");
a.add("2");
Iterator i$ = a.iterator();
do
{
if(!i$.hasNext())
break;
String temp = (String)i$.next();
if("1".equals(temp))
a.remove(temp);
} while(true);
场景一
List<String> a = new ArrayList<String>();
a.add("1");
a.add("2");
for (String temp : a) {
if("1".equals(temp)){
a.remove(temp);
}
}
执行结果
删除不会报错,但是循环只走了一次就结束了。
原因
for循环实际相当于使用迭代器遍历,在第一次循环时,执行完next()方法后游标置为1,即如下代码中第9行 cursor = 1
public E next() {
checkForComodification();
int i = cursor;
if (i >= size)
throw new NoSuchElementException();
Object[] elementData = ArrayList.this.elementData;
if (i >= elementData.length)
throw new ConcurrentModificationException();
cursor = i + 1;
return (E) elementData[lastRet = i];
}
接着执行remove(),执行成功后 size-1。
进行下次循环时执行hasNext()判断是否存在下一个元素时 满足cursor!=size 为true
,因此循环结束,代码如下:
public boolean hasNext() {
return cursor != size;
}
场景二
List<String> a = new ArrayList<String>();
a.add("1");
a.add("2");
for (String temp : a) {
if("2".equals(temp)){
a.remove(temp);
}
}
执行结果
删除之后,报错。
原因
for 在第二次循环中,执行完remove(),size=1,此时因为循环执行过两次,因此 此时cursor = 2,在进行第三次循环前 会执行 hasNext(),此时size != cursor 成立,导致 hasNext() 结果为true ,进入循环,然后执行next()方法。
next()方法会判断修改次数与预期修改次数是否相等,因为直接调用ArrayList的remove方法修改了modCount(+1)但不会修改得迭代器中的 expectedModCount的值,因此 出现
ConcurrentModificationException
final void checkForComodification() {
if (modCount != expectedModCount)
throw new ConcurrentModificationException();
}