java開發:java集合(七):迭代器的fail-fast(快速失敗)機制

Inteator 是頂層的迭代器接口,定義了迭代器共同的方法。hasNext()判斷集合是否含有下一個元素,next()獲取下一個元素。每個具體的集合類中都有一個迭代器內部類實現於Inteator接口,用來歷遍集合。

爲了方便獲取迭代器對象,java還提供了Iterable接口,使用iterator()方法來獲取集合的迭代器。Collection 繼承於Iterable接口,而所有具體的集合類都實現了Collection 。因此在我們使用集合時只需要調用集合對象的iterator()方法便可以得到迭代器對象。

/**
迭代器頂層接口
**/
public interface Inteator {
	public abstract boolean hasNext();
	public abstract Object next();
}

/**
獲取迭代器對象的頂層接口
**/
public interface Iterable {
	Iterator iterator();
}

/**
Collection接口 繼承Iterable
**/
public interface Collection extends Iterable {
	Iterator iterator();
}
public interface List extends Collection {
	Iterator iterator();
}
public calss ArrayList implements List {
	public Iterator iterator() {
		return new Itr();
	}
	private class Itr implements Iterator { //接口的具體實現類
		//包含了 所需功能  next()    hasNext() 等
	}
}

既然我們大概明白了迭代器的一個整體結構,我們來使用試一下:

   ArrayList<String> list = new ArrayList<>();
        list.add("1");
        list.add("2");
        list.add("3");
        list.add("4");
        //獲取迭代器
        Iterator iterator = list.iterator();
        //歷遍集合
        while (iterator.hasNext()) {
            Log.e("iterator",iterator.next().toString());
        }
2019-12-27 14:22:17.069 6360-6360/com.example.serializationapplication E/iterator: 1
2019-12-27 14:22:17.069 6360-6360/com.example.serializationapplication E/iterator: 2
2019-12-27 14:22:17.069 6360-6360/com.example.serializationapplication E/iterator: 3
2019-12-27 14:22:17.069 6360-6360/com.example.serializationapplication E/iterator: 4

實驗成功,可以迭代我們集合的所有元素,那麼我們試試在迭代過程中修改集合會怎麼樣?

  ArrayList<String> list = new ArrayList<>();
        list.add("1");
        list.add("2");
        list.add("3");
        list.add("4");
        //獲取迭代器
        Iterator iterator = list.iterator();
        //歷遍集合
        while (iterator.hasNext()) {
            Log.e("iterator",iterator.next().toString());
            //移除第一個元素
            list.remove(0);
        }

控制檯報出了異常: java.lang.RuntimeException: Unable to start activity ComponentInfo{com.example.serializationapplication/com.example.Main3Activity}: java.util.ConcurrentModificationException

解析ArrayList的迭代器源碼:

 private class Itr implements Iterator<E> {
        int cursor;       // 記錄元素下標的指針
        int lastRet = -1; // 記錄當前元素下標位置的指針
        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();
            //指針+1,指向下一個元素
            cursor = i + 1;
            //返回當前元素,修改lastRet 指向當前的元素
            return (E) elementData[lastRet = i];
        }

        public void remove() {
        	//當lastRet小於0則集合爲null
            if (lastRet < 0)
                throw new IllegalStateException();
            checkForComodification();

            try {
            	//刪除元素
                ArrayList.this.remove(lastRet);
                cursor = lastRet;
                lastRet = -1;
                //更新集合修改次數的索引
                expectedModCount = modCount;
            } catch (IndexOutOfBoundsException ex) {
                throw new ConcurrentModificationException();
            }
        }
    @Override
        @SuppressWarnings("unchecked")
        public void forEachRemaining(Consumer<? super E> consumer) {
            Objects.requireNonNull(consumer);
            final int size = ArrayList.this.size;
            int i = cursor;
            if (i >= size) {
                return;
            }
            final Object[] elementData = ArrayList.this.elementData;
            if (i >= elementData.length) {
                throw new ConcurrentModificationException();
            }
            while (i != size && modCount == expectedModCount) {
                consumer.accept((E) elementData[i++]);
            }
            // update once at end of iteration to reduce heap write traffic
            cursor = i;
            lastRet = i - 1;
            checkForComodification();
        }

        final void checkForComodification() {
        	//判斷迭代過程中集合是否倍修改
            if (modCount != expectedModCount)
                throw new ConcurrentModificationException();
        }
    }

可以看出在ItrArrayList的一個內部類,迭代器操作通過這個內部類,Itr有個expectedModCount屬性,這個屬性判斷是否與modCount相等,如果不相等拋出異常,modCount則是記錄list結構上發生變化的次數,可以看出在迭代時候checkForComodification()方法檢測兩個的值不相等就拋出異常。則出現這個異常的時候一般都是在迭代過程中改變了集合,導致modCountexpectedModCount屬性不相等。迭代器則提供了remove()方法來移除元素,在刪除元素後同時更新modCountexpectedModCount屬性,因此不會報異常。

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章