foreach循环中remove引起java.util.ConcurrentModificationException异常

来源:互联网 发布:广州知行通航 编辑:程序博客网 时间:2024/06/10 16:26

1.引起异常代码


public void test1(){    List<String> list = new ArrayList<String>();    list.add("2");    list.add("2");    list.add("2");    for (String temp : list) {        if ("2".equals(temp)) {            list.remove(temp);        }    }}



2.上面代码经过编译再反编译去除语法糖后,得到以下代码


   public void test1() {      ArrayList list = new ArrayList();      list.add("2");      list.add("2");      list.add("2");      Iterator var3 = list.iterator();      while(var3.hasNext()) {         String i = (String)var3.next();         if("2".equals(i)) {            list.remove(i);         }      }   }



可以看出,经过编译后,list类型的foreach循环实质上是使用了iterator。但是,循环体中的remove依然是直接使用ArarryList的remove,而不是iterator的。下面我们看下相关的源码,便可知道报错的原因。

3.ArarryList的remove源码

public boolean remove(Object o) {        if (o == null) {            for (int index = 0; index < size; index++)                if (elementData[index] == null) {                    fastRemove(index);                    return true;                }        } else {            for (int index = 0; index < size; index++)                if (o.equals(elementData[index])) {                    fastRemove(index);                    return true;                }        }        return false;}private void fastRemove(int index) {        modCount++; //修改次数        int numMoved = size - index - 1;        if (numMoved > 0)             //将除了被remove的元素之后复制回原来集合             System.arraycopy(elementData, index+1, elementData, index,numMoved);         elementData[--size] = null;}



每次执行ArarryList的remove方法,都会将修改次数变量modCount+1

4.ArarryList的私有内部类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;        }        @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();        }    }



内部类Itr中的remove方法实际上是先调用了ArrayList的remove,再将修改次数modCount同步到内部类的expectedModCount ,保持两者一致。

明显,问题代码是由于先调用了list.remove(),导致modCount和expectedModCount不相等,Itr执行next()时验证发现两个值不一致,抛出ConcurrentModificationException异常。因此,涉及到remove操作时应直接使用iterator,不可使用foreach语法糖。


阅读全文
0 0
原创粉丝点击