为什么iterator,foreach遍历时不能进行remove操作?

Exception in thread "main" java.util.ConcurrentModificationException 并发修改异常引发的思考!

①list遍历删除元素时会报错,比如下面删除字符串"aa",也有遍历不报错的例子,看下面的例子

public class TestMain {
    public static void main(String[] args) {
        ArrayList<String> array = new ArrayList<String>();
        array.add("cc");
        array.add("aa");
        array.add("bb");
        array.add("aa");   
        for (String str : array) {
            if("aa".equals(str)){
                array.remove(str);
            }
        }

        System.out.println(array.size());

    }
}

console:   java.util.ConcurrentModificationException

②下面删除字符串"aa"不会报错

public class TestMain {
    public static void main(String[] args) {
        ArrayList<String> array = new ArrayList<String>();
        array.add("cc");
        array.add("aa");
        array.add("bb");
        for (String str : array) {
            if("aa".equals(str)){
                array.remove(str);
            }
        }

        System.out.println(array.size());

    }
}

console : 2

③ 索引删除元素

public class TestMain {
    public static void main(String[] args) {
        ArrayList<String> array = new ArrayList<String>();
        array.add("cc");
        array.add("aa");
        array.add("bb");
        array.add("aa");
        for(int i = 0;i < array.size();i++){
            if("aa".equals(array.get(i))){
              array.remove(i);
            }
        }
        System.out.println(array.size());

    }
}

console:  2 

 

④ 迭代器删除元素

public static void main(String[] args) {

        ArrayList<String> array = new ArrayList<>();
        array.add("cc");
        array.add("aa");
        array.add("bb");
        array.add("ee");

        Iterator<String> iterator = array.iterator();
        while (iterator.hasNext()){
            String e = iterator.next();
            if("bb".equals(e)){
                iterator.remove();
            }
        }
    System.out.println(array.size());
}
console:  3

从上述执行结果可以得出:

① foreach遍历删除后,下一个循环会报错,源码如下红色字体

   
   // remove操作导致modCount++
   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; // clear to let GC do its work
     }

    // 删除元素后,遍历下一个元素会先校验,不通过,报错
    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]; }     final void checkForComodification() { if (modCount != expectedModCount) throw new ConcurrentModificationException(); }

 

② foreach遍历删除后,未报错?

其实原因很简单,因为第二个例子没有走iterator的next方法,删除了字符串"aa"之后,执行hasNext方法返回false直接退出遍历了,hasNext中就是判断cursor != size;此时的cursor是2,而size正好也是2,所以退出了遍历。

 

 

③ for循环删除,不会报错,按照索引删除

 

④ 迭代器的方式遍历,iterator.remove方法删除

 

 总结:  1 foreach遍历,iterator遍历都不能在遍历的过程中使用list.remove或list.add操作,会报并发修改异常,遍历删除后加个break即可解决。

    2 iterator遍历过程中如果需要删除可以使用iterator提供的remove()方法。

    3 遍历根据元素索引删除是可行的。

以上属于个人心得,不对之处还望大佬指出。  

 

posted @ 2017-11-07 15:36  李勇888  阅读(4555)  评论(3编辑  收藏  举报