ArrayList remove删除元素
先看代码
ArrayList<String> list = new ArrayList<>();
list.add("Java");
list.add("Python");
for (String item : list) {
if(item.equals("Java")){
list.remove(item);
}
}
编译后
ArrayList<String> list = new ArrayList<>();
list.add("Java");
list.add("Python");
Iterator<String> iterator = list.iterator();
while (iterator.hasNext()) {
String next = iterator.next();
if ("Java".equals(next)) {
list.remove(next);
}
}
这种情况下只能删除第一个元素,删除第二个元素会报错
991行报错的地方代码
为什么会存在modCount 和 expectedModCount?
首先modCount 是记录这个集合被操作的次数 add一个元素会加一,remove一个元素也会加一
添加一个元素
删除一个元素
expectedModCount 是内部类Itr中的一个属性默认赋值为modCount
Itr内部类的部分代码
/**
* An optimized version of AbstractList.Itr
*/
private class Itr implements Iterator<E> {
int cursor; // index of next element to return
int lastRet = -1; // index of last element returned; -1 if no such
int expectedModCount = modCount;
Itr() {}
public boolean hasNext() {
return cursor != size;
}
@SuppressWarnings("unchecked")
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];
}
final void checkForComodification() {
if (modCount != expectedModCount)
throw new ConcurrentModificationException();
}
}
首先分析为什么删除第一个不会报错
ArrayList<String> list = new ArrayList<>();
list.add("Java");
list.add("Python");
Iterator<String> iterator = list.iterator();
while (iterator.hasNext()) {
String next = iterator.next();
if ("Java".equals(next)) {
list.remove(next);
}
}
注意hashNext方法
cursor(0) | size(2) | hasNext | checkForComodification | |
---|---|---|---|---|
第一次循环 | 0 | 2 | true | true |
第二次准备循环 | 1 | 1 | false | 不会进入 |
因为第一次循环if判断了两者相等 list 已经删除了Java 这个元素 size变成了1,由hasNext方法判断得出false 所以不会进入while循环。所以这只有一次循环。第二次准备循环是条件不满足退出了。
拿为什么删除第二个会报错
cursor(0) | size(2) | hasNext | checkForComodification | |
---|---|---|---|---|
第一次循环 | 0 | 2 | true | true |
第二次循环 | 1 | 2 | true | true |
第三次循环 | 2 | 1 | true | false 抛异常 |
第二次循环删除了一个元素 modCount+1 , size+1 ,cursor+1,所以hasNext是true ,在checkForComodification中 modCount !=expectedModCount所以会报错。
数学推理来了:
在单线程的情况下,只要你的ArrayList集合大小大于等于2(假设大小为n,即size=n),你删除倒数第二个元素的时候,cursor从0进行了n-1次的加一操作,size(即n)进行了一次减1的操作,所以n-1=n-1,即cursor=size。
因为判断条件返回为fales,虽然你的modCount变化了。但是不会进入下次循环,就不会触发modCount和expectedModCount的检查,也就不会抛出ConcurrentModifyException.
参考链接
【原创】这道Java基础题真的有坑!我求求你,认真思考后再回答
【原创】这道Java基础题真的有坑!我也没想到还有续集。