java.util.ConcurrentModificationException原因

義往昔 3月前 ⋅ 74 阅读

1.还原事故现场

ArrayList list = new ArrayList<>();
        for (int i = 0; i < 10; i++) {
            list.add(i);
        }
        Iterator iterator = list.iterator();
        ListIterator integerListIterator = list.listIterator();
        integerListIterator.next();
        while (iterator.hasNext()){
            Integer next = iterator.next();
            if (next == 3){
                list.remove(next);//java.util.ConcurrentModificationException
            }
            System.out.println(next);
        }

2.解析
上面简单模拟了异常出现的情况,下面看看异常出现的原因,从 

list.listIterator();进去
 public Iterator<E> iterator() {
        return new Itr();
    }
原来就是返回的Itr这个实现了Iterator接口的类
下面我们来看看这个类是怎么实现的,很简单(删减了和本次主题无关的东西)
 
private class Itr implements Iterator<E> {
        //集合的大小
        protected int limit = ArrayList.this.size;
        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 < limit;
        }

        @SuppressWarnings("unchecked")
        public E next() {
              //这里是报异常的地方,也就是当modCount!=expectedModCount的时候会报异常
              //我们看到,在这个类初始化的时候expectedModCount = modCount,
              //在使用next()或者hasNext()方法的时候没有改变expectedModCount的值
              //也就是说modCount的值改变,造成这两个值不一样了
              //通过查看ArrayList的增删等方法,发现没操作一次增删等方法,这个modCount就++
              //modCount就是记录的这个集合被修改的次数
              //因此我们就明白了为什么在使用iterator迭代的时候不能修改
            if (modCount != expectedModCount)
                throw new ConcurrentModificationException();
            int i = cursor;
            if (i >= limit)
                throw new NoSuchElementException();
            Object[] elementData = ArrayList.this.elementData;
            if (i >= elementData.length)
                throw new ConcurrentModificationException();
            cursor = i + 1;
            return (E) elementData[lastRet = i];
        }
        //但是我还想在迭代的时候进行删除操作怎么办?
        //那么就用下面这个方法,这个方法进行删除操作仍然会保证modCount == expectedModCount
        public void remove() {
            if (lastRet < 0)
                throw new IllegalStateException();
            if (modCount != expectedModCount)
                throw new ConcurrentModificationException();

            try {
                ArrayList.this.remove(lastRet);
                cursor = lastRet;
                lastRet = -1;
                expectedModCount = modCount;
                limit--;
            } catch (IndexOutOfBoundsException ex) {
                throw new ConcurrentModificationException();
            }
        }
      ...
    }
 
只有在list大小发生变化时候
list除了iterator()方法还有一个list.listIterator()方法
这个方法返回的iterator功能更强大,  比如可以增加一个值,可以更新一个值等. 可以往前 也可以往后
 
 

來源:简书


注意:本文归作者所有,未经作者允许,不得转载

全部评论: 0

    我有话说: