zoukankan      html  css  js  c++  java
  • foreach能不能add、remove ?

    1、现象

      增强for循环中进行remove、add会报ConcurrentModificationException

    2、原理

    • 增强for循环其实是交给iterator来完成增删改查的
    • 看下iterator的代码,如下
    /**
         * 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;
    
            Itr() {}
    
            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];
            }
    final void checkForComodification() {
                if (modCount != expectedModCount)
                    throw new ConcurrentModificationException();
            }

    因为remove 或者add 的时候会改变modCount的值,导致会报ConcurrentModificationException,remove 和 add代码如下:

        /*
         * 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; // clear to let GC do its work
        }
        public boolean add(E e) {
            ensureCapacityInternal(size + 1);  // Increments modCount!!
            elementData[size++] = e;
            return true;
        }
        private void ensureExplicitCapacity(int minCapacity) {
            modCount++;
    
            // overflow-conscious code
            if (minCapacity - elementData.length > 0)
                grow(minCapacity);
        }

    3、特殊现象

      增强for循环当删除倒数第二个元素的时候不会报错。

      原因:比如一个list有四个元素{1,2,3,4},此时cursor是3,remove过后size也是3,cursor != size就是false,下面代码不走,进不到next()中就不会报错。

     /**
         * 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;
    
            Itr() {}
    
            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();
                }
            }

    测试代码:

    public class Test {
        public static void main(String[] args) {
    
            List<Integer> list = new ArrayList<>();
            list.add(1);
            list.add(2);
            list.add(3);
            list.add(4);
    
    
            for (Integer temp : list) {
                System.out.println(temp);
                if (temp == 3) {
                    list.remove(temp);
                }
            }
        }
    }
    "C:Program FilesJavajdk1.8.0_192in...1
    2
    3
    
    Process finished with exit code 0
  • 相关阅读:
    [转自老马的文章]用MODI OCR 21种语言
    [转老马的文章]MODI中的OCR模块
    贴片晶振的脚位方向如何区分
    晶振简介及如何使用示波器测试晶振
    Lintcode 150.买卖股票的最佳时机 II
    Lintcode 82.落单的数
    Lintcode 97.二叉树的最大深度
    Lintcode 9.Fizz Buzz 问题
    LeetCode之461. Hamming Distance
    NYOJ之题目325 zb的生日
  • 原文地址:https://www.cnblogs.com/TripL/p/13359412.html
Copyright © 2011-2022 走看看