首先分析增强for循环或者迭代器遍历时候的next方法
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];
}
其中checkForComodification()方法会在遍历的时候检查这个集合修改的次数和遍历之前的次数是否一致,如果不一致则抛出异常
final void checkForComodification() {
if (modCount != expectedModCount)
throw new ConcurrentModificationException();
}
其中expectedModCount就是在迭代器遍历之前初始化时赋值的,就是修改次数的值modCount
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;
........
}
Ok,再看ArrayList中的remove方法或者add方法
public E remove(int index) {
rangeCheck(index);
modCount++;
E oldValue = elementData(index);
int numMoved = size - index - 1;
if (numMoved > 0)
System.arraycopy(elementData, index+1, elementData, index,
numMoved);
elementData[--size] = null; // clear to let GC do its work
return oldValue;
}
从代码中分析可以知道,当往数组中放入数据或者移除数据的时候都会将记录修改次数的变量modCount加一,在遍历的时候如果数组改变可能遍历获取的数据会有问题,所以会抛出异常.
如果想要解决遍历的时候,使用迭代器的remove()方法即可,下面看看是如何解决的
public void remove() {
if (lastRet < 0)
throw new IllegalStateException();
checkForComodification();
try {
ArrayList.this.remove(lastRet);
cursor = lastRet;
lastRet = -1;
expectedModCount = modCount;
} catch (IndexOutOfBoundsException ex) {
throw new ConcurrentModificationException();
}
}
上述代码可以清晰的看到使用迭代器remove会重新将modCount的值赋给expectedModCount,因此就不会跑并发修改的异常了.
在遍历时使用迭代器remove()测试:
public class ArrayListTest {
public static void main(String[] args) {
List<String> list = new ArrayList<>();
list.add("haha");
list.add("lala");
list.add("haha");
list.add("haha");
list.add("haha");
list.add("haha");
list.add("haha");
Iterator<String> iterator = list.iterator();
while(iterator.hasNext()){
String next = iterator.next();
System.out.println(next);
if (next.equals("lala")) {
// list.remove("lala");
iterator.remove();
}
}
}
}
结果如下:
"C:\Program Files\Java\jdk1.8.0_212\bin\java.exe"
haha
lala
haha
haha
haha
haha
haha
Process finished with exit code 0