Iterator之remove情况分析之一报错原因

在iterator过程中使用list.remove,报错Exception in thread "main" java.util.ConcurrentModificationException

package collect;

import java.util.ArrayList;
import java.util.Iterator;
import java.util.List;

public class myiterator {
public static void main(String[] args) {
     List<String> list =new ArrayList<String>();
     list.add("China");
     list.add("hello");
     list.add("world");
     Iterator<String> it =list.iterator();
     System.out.println(list.size());
     
     int i = 0,j=0;
     while (it.hasNext()) {
        it.next();
         i++;
         list.remove("hello");
        System.out.println("运行第"+i+"次");    
    }    
}
}

结果

3
运行第1次
Exception in thread "main" java.util.ConcurrentModificationException
    at java.util.ArrayList$Itr.checkForComodification(Unknown Source)
    at java.util.ArrayList$Itr.next(Unknown Source)
    at collect.myiterator.main(myiterator.java:18)

同时修改异常,就是在iterator运行过程中,因为list修改而报错的异常

源代码的角度来说:当arrarlist调用iterator的时候,返回一个Itr的引用

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

在arraylist中找到Itr的类

private class Itr
    implements Iterator<E>
  {
    int cursor;
    int lastRet = -1;
    int expectedModCount = modCount;
    
    private Itr() {}
    
    public boolean hasNext()
    {
      return cursor != size;
    }
    
    public E next()
    {
      checkForComodification();
      int i = cursor;
      if (i >= size) {
        throw new NoSuchElementException();
      }
      Object[] arrayOfObject = elementData;
      if (i >= arrayOfObject.length) {
        throw new ConcurrentModificationException();
      }
      cursor = (i + 1);
      return (E)arrayOfObject[(lastRet = i)];
    }
    
    public void remove()
    {
      if (lastRet < 0) {
        throw new IllegalStateException();
      }
      checkForComodification();
      try
      {
        remove(lastRet);
        cursor = lastRet;
        lastRet = -1;
        expectedModCount = modCount;
      }
      catch (IndexOutOfBoundsException localIndexOutOfBoundsException)
      {
        throw new ConcurrentModificationException();
      }
    }

 

checkForComodification();这个方法

final void checkForComodification()
    {
      if (modCount != expectedModCount) {
        throw new ConcurrentModificationException();
      }
    }

判断一下modCount != expectedModCount是否相等,不等的话抛出ConcurrentModificationException();

modCount属于 AbstractList<E>类的protected transient int modCount = 0;初始为0

expectedModCount属于ArrayList<E>下面的Itr类的

int expectedModCount = modCount;

当arraylist调用remove方法时,调用的是arraylist下面的remove跟fastRemove对应方法

public E remove(int paramInt)
  {
    rangeCheck(paramInt);
    modCount += 1;
    Object localObject = elementData(paramInt);
    int i = size - paramInt - 1;
    if (i > 0) {
      System.arraycopy(elementData, paramInt + 1, elementData, paramInt, i);
    }
    elementData[(--size)] = null;
    return (E)localObject;
  }
  
  public boolean remove(Object paramObject)
  {
    int i;
    if (paramObject == null) {
      for (i = 0; i < size; i++) {
        if (elementData[i] == null)
        {
          fastRemove(i);
          return true;
        }
      }
    } else {
      for (i = 0; i < size; i++) {
        if (paramObject.equals(elementData[i]))
        {
          fastRemove(i);
          return true;
        }
      }
    }
    return false;
  }
  
  private void fastRemove(int paramInt)
  {
    modCount += 1;
    int i = size - paramInt - 1;
    if (i > 0) {
      System.arraycopy(elementData, paramInt + 1, elementData, paramInt, i);
    }
    elementData[(--size)] = null;
  }

 

当调用remove(int paramInt)时,modCount+= 1;会+1改变modCount 的值

当调用remove(Object paramObject) ,会调用fastRemove(int paramInt) 接着modCount += 1;会+1改变modCount 的值

总之,ArrayList<E>下面的remove方法会改变modCount的值,remove一次,使其+1一次

总结:现在从头看一下,当Iterator<String> it =list.iterator();时,创建一个Itr引用

并且内部int expectedModCount = modCount;,来自于AbstractList<E>   的protected transient int modCount = 0;

现在expectedModCount跟modCount都等于0,在执行完arraylist的remove方法后modCount值+1,

然后程序执行iterator.next(); 其中checkForComodification()判断expectedModCount跟modCount值不等,然后thrownew ConcurrentModificationException();

同样在iterator里面进行list.add也会导致modCount值+1  报错

add方法每次都会ensureCapacityInternal确保容量够用

public boolean add(E paramE)
  {
    ensureCapacityInternal(size + 1);
    elementData[(size++)] = paramE;
    return true;
  }
  
  public void add(int paramInt, E paramE)
  {
    rangeCheckForAdd(paramInt);
    ensureCapacityInternal(size + 1);
    System.arraycopy(elementData, paramInt, elementData, paramInt + 1, size - paramInt);
    elementData[paramInt] = paramE;
    size += 1;
  }

然后这里面就会执行modCount += 1;

private void ensureCapacityInternal(int paramInt)
  {
    if (elementData == DEFAULTCAPACITY_EMPTY_ELEMENTDATA) {
      paramInt = Math.max(10, paramInt);
    }
    ensureExplicitCapacity(paramInt);
  }
  
  private void ensureExplicitCapacity(int paramInt)
  {
    modCount += 1;
    if (paramInt - elementData.length > 0) {
      grow(paramInt);
    }
  }

这里面是判断是否存在对象,

假如list里面什么都没有因为iterator.hasNext()都进不去,在iterator里面可以写list.add方法,不过东西加入到list的里面,输出结果还是为空,

如果list存在值这时进入iterator遍历,先判断是否存在,不过hasNext()判断过了,肯定存在

if (elementData == DEFAULTCAPACITY_EMPTY_ELEMENTDATA) {
      paramInt = Math.max(10, paramInt);
    }

所以一定执行ensureExplicitCapacity,modCount+= 1;,导致iterator里面list.add失败

相关内容:

forEach内部实现原理,也无法执行list.add与remove分析

如何实现在iterator内部remove

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值