JAVA循环迭代中删除或添加集合数据报java.util.ConcurrentModificationException错误

1.写出下面的输出结果

public class test{
  public static void main(String [] args)

   List<String> list = new ArrayList<String>();

   for (int i = 0; i < 10; i++) {
     list.add(String.valueOf(i));
   }
   for(String s : list){
    if(s.equals("3")){
      list.remove(s);
    }
   }
  System.out.println(list.size());

  }

}

正确的输出:发生了并发的错误

java.util.ConcurrentModificationException
at java.util.ArrayList$Itr.checkForComodification(Unknown Source)
at java.util.ArrayList$Itr.next(Unknown Source)
at test.main(test.java:35)

在这里for(String s : list){}的实质还是Iterator接口。

上面这段代码等价于下面:

Iterator<String> iterator = list.iterator();
while(iterator.hasNext()){
  String itString = (String)iterator.next();
  if (itString.equals("3")) {
    list.remove(itString); --这里会报错

    //iterator.remove();---这里不会报错

  }
}

所以我们来看看 list.iterator();的源码就知道为什么了

public Iterator<E> iterator() {
  return new Itr();
}

/**
* An optimized version of AbstractList.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();
  }
}

从源码上我们可以看出,当我们调用next()方法的时候有一个检查modCount != expectedModCount;然后我们再来看看ArrayList的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 remove method that skips bounds checking and does not
* return the value removed.
*/
private void fastRemove(int index) {
  modCount++;
  int numMoved = size - index - 1;
  if (numMoved > 0)
    System.arraycopy(elementData, index+1, elementData, index,
    numMoved);
  elementData[--size] = null; // Let gc do its work
}

从上面的代码中可以看出当我们进行remove的时候modeCount的值发生了变化,这就导致和expectedModCount的值相等了,故报错。

从源码中我们还得知,在clear方法,add方法,addAll方法,removeRange方法时都会导致modeCount的值发生变化。

所以当我们想在循环中对List进行删除时不能用List的remove*方法。但是可以用iterator.remove();从上面的源码中我们可以知道这个方法中进行了

expectedModCount=ModCount对expectedModCount重新赋值。

上一篇:【转】http-equiv="X-UA-Compatible" 设置IE浏览器兼容模式详解


下一篇:AngularJS之WebAPi上传(十)