本文共 3590 字,大约阅读时间需要 11 分钟。
冲天香阵透长安,满城尽带黄金甲
上次在写代码时,使用迭代器遍历一个集合,并在迭代中移除(或下新增)集合中的某项,就会出现ConcurrentModificationException异常。
问题代码
public static void main(String[] args) { //定义一个集合 Listlist = new ArrayList<>(); //给集合添加数据 list.add("a"); list.add("b"); list.add("c"); //迭代集合 Iterator iterator = list.iterator(); while(iterator.hasNext()) { //拿到集合中的下一个值 String next = iterator.next(); System.out.println(next); //移除集合中索引为1的数据 list.remove(1); } }
异常信息
Exception in thread "main" java.util.ConcurrentModificationException at java.util.ArrayList$Itr.checkForComodification(ArrayList.java:859) at java.util.ArrayList$Itr.next(ArrayList.java:831)
从异常信息中可以看出,是由next方法调用checkForComodification方法抛出的异常,接着我们找到ArrayList子类Itr下的next和checkForComodification方法,如下:
private class Itr implements Iterator{ 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; } @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]; } 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(); } } final void checkForComodification() { if (modCount != expectedModCount) throw new ConcurrentModificationException(); } }
可以看到,在调用next方式,会先调用checkForComodification方法判断集合修改的次数和预期的值是否一致,不一致则会抛出ConcurrentModificationException异常。由控制台打印的信息可以看出,modCount != expectedModCount
,即抛出了该异常。
modCount != expectedModCount
,说明这个问题,我们接着看remove方法: 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; }
可以看到,在remove方法中,执行了modCount++;
,使得modCount的值加了1,而expectedModCount并没有变化,所以在remove之后,调用next时,next方法又调用checkForComodification判断方法,此时,modCount != expectedModCount
,就抛出了异常。
解决这个问题也很简单,将代码中的//移除集合中索引为1的数据 list.remove(1);
改为迭代器的remove方法即可,即:iterator.remove();
。我们来看看迭代器的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(); }}
方法里面有expectedModCount = modCount;
赋值操作,所以,在checkForComodification判断时就不会出异常了。
转载地址:http://ywiib.baihongyu.com/