-
传统方式下的Collection在迭代集合时,不允许对集合进行修改。
-
根据AbstractList的checkForComodification方法的源码,分析产生ConcurrentModificationException异常的原因
传统方式下的Collection在迭代集合时,不允许对集合进行修改。
根据AbstractList的checkForComodification方法的源码,分析产生ConcurrentModificationException异常的原因
情况1:删除倒数一个元素
ArrayList<String> list = new ArrayList<String>();
list.add("张三");
list.add("李四");
list.add("王五");
// 迭代的时候删除数据--看是否报异常
Iterator<String> iterator = list.iterator();
while (iterator.hasNext()) {
String name = iterator.next();
if (name.equals("李四")) {
list.remove(name);
}
System.out.println(name);
}
输出:
张三
李四
情况2:删除开头或中间元素
// 添加数据--三个
ArrayList<String> list = new ArrayList<String>();
list.add("张三");
list.add("李四");
list.add("王五");
// 迭代的时候删除数据--看是否报异常
Iterator<String> iterator = list.iterator();
while (iterator.hasNext()) {
String name = iterator.next();
if (name.equals("张三")) {
list.remove(name);// 注意:这里调用的时候List的remove方法,而不是Iterator的方法。 删除“张三”或“王五”均会出现异常
}
System.out.println(name);
}
张三
java.util.ConcurrentModificationException
at java.util.ArrayList$Itr.checkForComodification(ArrayList.java:901)
at java.util.ArrayList$Itr.next(ArrayList.java:851)
at com.edu.fzu.googleplay.ExampleUnitTest.addition_isCorrect(ExampleUnitTest.java:23)
问1:为何情况1和情况2出现不同情况:---分析源代码,重点分析整个调用过程中调用的函数(hasNext和remove)
// 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;
public boolean hasNext() {
return cursor != size; // size为集合中元素的个数
}
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];
}
/* 此方法并没被调用,只是调用List.remove方法
public void remove() {
checkForComodification();
try {
ArrayList.this.remove(lastRet);// size字段减1
cursor = lastRet;
lastRet = -1;
expectedModCount = modCount;
} catch (IndexOutOfBoundsException ex) {
throw new ConcurrentModificationException();
}
}
*/
final void checkForComodification() {// 检查修改和当前版本号是否一致,不一致则抛出异常
if (modCount != expectedModCount)
throw new ConcurrentModificationException();
}
}
// List.remove
@Override public boolean remove(Object object) {
Object[] a = array;
int s = size;
if (object != null) {
for (int i = 0; i < s; i++) {
if (object.equals(a[i])) {
System.arraycopy(a, i + 1, a, i, --s - i);
a[s] = null; // Prevent memory leak
size = s;
modCount++;// 核心代码:修改了版本号。这样当checkForComodification的时候,modCount值就和expectedModCount不同
return true;
}
}
} else {
for (int i = 0; i < s; i++) {
if (a[i] == null) {
System.arraycopy(a, i + 1, a, i, --s - i);
a[s] = null; // Prevent memory leak
size = s;
modCount++;
return true;
}
}
}
return false;
}
答1:
出现情况1原因:当name为“李四”的时候,执行remove方法,此时size减1(变为2),此时再次执行hasNext的时候cursor为2,size也为2
所以就打印两次:张三,李四。然后退出,没报异常
出现情况2原因:
当调用remove方法的时候修改了modCount值(参考源代码),这样导致expectedModCount和modCount不同,这样下次checkForComodification就抛出异常