list的数据遍历时的删除错误及其解决办法

在遍历list而且特定条件下需要删除刚刚遍历完的一个元素时调用的remove(object)会报如下错误:主要是因为Iterator 是工作在一个独立的线程中,并且拥有一个 mutex 锁。 Iterator 被创建之后会建立一个指向原来对象的单链索引表,当原来的对象数量发生变化时,这个索引表的内容不会同步改变,所以当索引指针往后移动的时候就找不到要迭代的对象,所以按照 fail-fast 原则 Iterator 会马上抛出 java.util.ConcurrentModificationException 异常。Iterator 在工作的时候是不允许被迭代的对象被改变的。但你可以使用 Iterator 本身的方法 remove() 来删除对象, Iterator.remove() 方法会在删除当前迭代对象的同时维护索引的一致性。是在于foreach方式遍历元素的时候,是生成iterator,然后使用iterator遍历。在生成iterator的时候,会保存一个expectedModCount参数,这个是生成iterator的时候List中修改元素的次数。如果你在遍历过程中删除元素,List中modCount就会变化,如果这个modCount和exceptedModCount不一致,就会抛出异常,这个是为了安全的考虑。

foreach的remove(Object)的源码:

  • 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;
  • }
    没有对expectedModCount进行任何修改,导致expectedModCount和modCount不一致,抛出异常。
     
    iterear的remove()源码
    • public void remove() {
    • if (lastRet < 0)
    • throw new IllegalStateException();
    • checkForComodification();
    •  
    •  
    • try {
    • ArrayList. this.remove(lastRet);
    • cursor = lastRet;
    • lastRet = - 1;
    • expectedModCount = modCount; //处理expectedModCount
    • } catch (IndexOutOfBoundsException ex) {
    • throw new ConcurrentModificationException();
    • }
    • }
      对expectedModCount重新做了赋值处理的。这样的话保持expectedModCount = modCount相等,就不会报出错了。

猜你喜欢

转载自www.cnblogs.com/daqq/p/9245494.html