Java_foreach不能remove

foreach

阿里巴巴java开发手册

【强制】不要在foreach循环里进行元素的remove/add操作。remove元素请使用Iterator方式,如果并发操作,需要对Iterator对象加锁。

反例
 List<String> a = new ArrayList<String>(); 
 a.add("1");
 a.add("2");
 for (String temp : a) { 
    if("1".equals(temp)){
         a.remove(temp); 
     } 
 } 
 正例
 Iterator<String> it= a.iterator(); 
while(it.hasNext()){ 
    String temp = it.next(); 
    if(删除元素的条件){ 
        it.remove(); 
    } 
}

foreach源码

foreach遍历集合,其实是走的Iterator,首先判断hasNext(),如果没有了则终止循环,否则next()获取元素时,next()时,都要check一下集合元素个数是否变化了,如果变化了,则抛出异常。

Itr是ArrayList的内部类,实现了Iterator接口

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;//游标不等于元素个数就是还有下一个
 }

public E next() {
     checkForComodification();//check是否并发修改
      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();
  }
}

modCount是集合添加元素、删除元素的次数,expectedModCount是预期的修改次数。增删操作会使得modCount+1,不等于expetedModCount,所以抛出异常。

没有使用list.iterator时调用的是ArrayList自己的remove,并不会同步这两个值,导致抛出异常。调用了ArrayList.iterator之后,然后了Itr对象,此后再remove,remove方法中有让这两个值相等的操作。

迭代器方式移除

那为什么Iterator不会异常呢?

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方法会修改expectedModCount,从而使modCount与之相等

参考:https://blog.csdn.net/wangjun5159/article/details/61415358

原文地址:https://www.cnblogs.com/AganRun/p/11816053.html