首先,先看一下这段代码
List<String> list = new ArrayList<>();
list.add("111");
list.add("222");
list.add("333");
Iterator<String> iterator = list.iterator();
while(iterator.hasNext()){
String next = iterator.next();
if(next.equals("222")){
list.add("444");
}
}
这段代码看起来好像没什么问题,但是运行这段代码就会报出ConcurrentModificationException异常,根据异常提示我们来到ArrayList的源码看到下面这段代码:
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();
}
当我们调用到iterator.next()方法时,就会调用到这个checkForComodification()方法。在这里会比较modCount和expectedModCount的值,如果不相等就会抛出异常。在这段代码中的modCount其实就是集合实际的修改次数,而expectedModCount是集合预期修改次数,这两个值是从哪来的呢,我们接着看源码。
public Iterator<E> iterator() {
return new 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;
我们看到在源码中是将modCount的值赋给了expectedModCount,按理来说这两个值应该就是相等的,这时候我们看一下自己写的代码:
while(iterator.hasNext()){
String next = iterator.next();
if(next.equals("222")){
list.add("444");
}
}
我们在这里还用了add()方法,于是我们去ArrayList的add方法源码与看了一下,代码如下:
public boolean add(E e) {
ensureCapacityInternal(size + 1); // Increments modCount!!
elementData[size++] = e;
return true;
}
private void ensureCapacityInternal(int minCapacity) {
if (elementData == DEFAULTCAPACITY_EMPTY_ELEMENTDATA) {
minCapacity = Math.max(DEFAULT_CAPACITY, minCapacity);
}
ensureExplicitCapacity(minCapacity);
}
private void ensureExplicitCapacity(int minCapacity) {
modCount++;
// overflow-conscious code
if (minCapacity - elementData.length > 0)
grow(minCapacity);
}
我们看到这里有一个modCount++,OK,真相大白了,原来用到add()方法会使List集合的实际修改次数modCount改变,这个时候再调用next()方法就会进行比较modCount和expectedModCount的值,因为modCount的值已经改变了,就会抛出ConcurrentModificationException异常了。