Java集合 iterator.remove()方法詳解

直接上代碼:java

public class test {
    public static void main(String[] args) {
        List<Integer> list = new ArrayList<>();
        for (int i = 0 ; i < 10 ; i++ ) {
            list.add(i);
        }
        Iterator<Integer> iterator = list.iterator();
        int i = 0 ;
        while(iterator.hasNext()) {

            if (i == 3) {
                iterator.remove(); //報java.lang.IllegalStateException異常
            }
            i ++;
        }
        System.out.println(list);
    }
}

爲何會報異常呢,經過一些查資料或者基礎較好的讀者知道只須要使用調用迭代器iterator.next()方法便可返回當前元素,因此只須要在remove()方法前面加上this

iterator.next();

注意這裏有人會使用int x = iterator.next();這樣來把當前的索引賦值而後再進行操做,其實這樣是不必的,咱們來根據這個例子深刻的瞭解一下iterator的源碼是如何實現的。code

首先咱們調用的是list.iterator()方法來獲取這個迭代器,固然list類並無實現這個方法,咱們最終是使用它的子類ArrayList來獲取迭代器:對象

/**
     * Returns an iterator over the elements in this list in proper sequence.
     *
     * <p>The returned iterator is <a href="#fail-fast"><i>fail-fast</i></a>.
     *
     * @return an iterator over the elements in this list in proper sequence
     */
    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;

        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();
            }
        }

能夠看到,iterator()方法返回了一個Itr對象,接着下面,Itr是一個內部類,而且實現了Itertor接口。索引

回到咱們最初的問題,爲何在迭代器中不用在不使用next()方法狀況下進行remove操做會出錯?咱們來看下remove()方法源碼,接口

在remove方法第一行,便可看到:element

if (lastRet < 0)
                throw new IllegalStateException();

當lastRet < 0的狀況下,會拋出IllegalStateException異常,那麼這個lastRet是什麼呢,其實在Itr類就定義了這個lastRet變量,和它一塊兒的還有cursor,expectedModCount;rem

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;

 經過註釋能夠看到,lastRet就是上個元素的索引,默認是-1,因此直接調用迭代器的remove()方法會報錯就是這個緣由,源碼

因此在上面的next()方法裏,咱們能夠看到這樣的代碼:博客

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];

它會把cursor遊標賦值給i,而後進行+1操做,最後將lastRet賦值成i,因此lastRet就不是默認的-1了,而是會獲得上個元素的索引,

因此綜合上述的結論,在使用迭代器iterator.remove()方法前,必定先調用next()方法來給變量lastRet進行賦值操做,

還有讀者或許會問,爲何要使用迭代器的remove()方法,而不是使用集合自身的remove(),add()等方法呢,能夠閱讀個人另外一片博客。

相關文章
相關標籤/搜索