• 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重新赋值。

  • 相关阅读:
    Spark学习--SparkCore03
    2D特效和3D特效
    CSS3选择器在HTML5中的使用
    HTML5中表单中新增加元素
    HTML5简介
    机器学习系列:
    机器学习系列:
    机器学习系列:
    机器学习系列:
    机器学习系列:
  • 原文地址:https://www.cnblogs.com/javatech/p/3650459.html
Copyright © 2020-2023  润新知