常見Java集合實現細節——Iterator迭代器

4、Iterator迭代器

       Iterator是一個迭代器接口,專門用於迭代器各種Collection集合,包括Set集合和List集合。

4、1 Iterator實現類與迭代器模式

import java.util.ArrayDeque;
import java.util.ArrayList;
import java.util.EnumSet;
import java.util.HashSet;
import java.util.LinkedHashSet;
import java.util.LinkedList;
import java.util.TreeSet;
import java.util.Vector;

enum Sex{
	FEMALE , MALE;
}

public class IteratorTest {
	public static void main(String[] args) {
		HashSet<String> hashSet = new HashSet<>();
		System.out.println("HashSet的Iterator:" + hashSet.iterator());
		
		LinkedHashSet<String> linkedHashSet = new LinkedHashSet<>();
		System.out.println("LinkedHashSet的Iterator:" + linkedHashSet.iterator());
		
		TreeSet<String> treeSet = new TreeSet<>();
		System.out.println("TreeSet的Iterator:" + treeSet.iterator());
		
		EnumSet<Sex> enumSet = EnumSet.allOf(Sex.class);
		System.out.println("EnumSet的Iterator:" + enumSet.iterator());
		
		ArrayList<String> arrayList = new ArrayList<>();
		System.out.println("ArrayList的Iterator:" + arrayList.iterator());
		
		Vector<String> vector = new Vector<>();
		System.out.println("Vector的Iterator:" + vector.iterator());
		
		LinkedList<String> linkedList = new LinkedList<>();
		System.out.println("LinkedList的Iterator:" + linkedList.iterator());
		
		ArrayDeque<String> arrayDeque = new ArrayDeque<>();
		System.out.println("ArrayDeque的Iterator:" + arrayDeque.iterator());
	}
}
輸出結果爲:
HashSet的Iterator:java.util.HashMap$KeyIterator@2a36bb87
LinkedHashSet的Iterator:java.util.LinkedHashMap$KeyIterator@5511e28
TreeSet的Iterator:java.util.TreeMap$KeyIterator@2198a037
EnumSet的Iterator:java.util.RegularEnumSet$EnumSetIterator@119fdafc
ArrayList的Iterator:java.util.ArrayList$Itr@1b219665
Vector的Iterator:java.util.Vector$Itr@3a18cecd
LinkedList的Iterator:java.util.LinkedList$ListItr@2e4f7bc2
ArrayDeque的Iterator:java.util.ArrayDeque$DeqIterator@15136019
       從上面運行的結果可以看出,除了EnumSet集合的Iterator就是RegularEnumSet的一個內部類之外,所有Set集合對應的Iterator都是它對應的Map類的內部類KeyIterator。這是因爲,Set集合底層是通過Map來實現的。
       通過上面的介紹可以得出,對應Iterator迭代器而言,它僅僅只是一個接口。Java要求各種集合都提供一個iterator()方法,該方法可以返回一個Iterator用於遍歷該集合中的元素,至於返回的Iterator到底是哪種實現類,程序並不關心,這就是定性的“迭代器模式”。
提示:迭代器模式指的是:系統爲遍歷多種數據列表、集合、容器提供一個標準的“迭代器接口”,這些數據列表、集合、容器就可面向相同的“迭代器接口”編程,通過相同的迭代器接口訪問不同數據列表、集合、容器裏的數據。不同的數據列表、集合、容器如何實現這個“迭代器接口”,則交給各數據列表、集合、容器自己完成。

4、2 迭代時刪除指定的元素

       由於Iterator迭代器只負責對各種集合中所包含的元素進行迭代,但迭代器本身並沒有保留集合元素,因此使用Iterator進行迭代時,通常不應該刪除集合元素,否則將引發ConcurrentModificationException異常。當然,Java允許通過Iterator提供的remove()方法刪除剛剛迭代的集合元素。
import java.util.ArrayList;
import java.util.Iterator;


public class ArrayListRemove {
	public static void main(String[] args) {
		ArrayList<String> list = new ArrayList<>();
		list.add("123");
		list.add("456");
		list.add("789");
		for ( Iterator<String> it = list.iterator() ; it.hasNext() ; ) {
			String e = it.next();
			System.out.println(e);
			if ( e.equals("456") ) {  //①
				list.remove(e);
			}
		}
	}
}
輸出結果:
123
456
       上面程序中直接調用了List的remove()方法刪除指定的集合元素。運行上面的程序,發現該程序完全可以正常結束,並未引發任何異常。
       實際上,對於ArrayList、Vector、LinkedList等List集合而言,當使用Iterator遍歷時,如果正在遍歷倒數第二個集合元素,那麼使用List結合的remove()方法刪除集合的任意一個元素並不會引發ConcurrentModificationException異常,當正在遍歷其他元素時刪除其他元素就會引發該異常。也就是說,如果將程序中的①行代碼改爲等於其他元素,就會引發ConcurrentModificationException異常。
import java.util.Iterator;
import java.util.TreeSet;

public class TreeSetRemove {
	public static void main(String[] args) {
		TreeSet<String> set = new TreeSet<>();
		set.add("123");
		set.add("456");
		set.add("789");
		for ( Iterator<String> it = set.iterator() ; it.hasNext() ; ) {
			String e = it.next();
			System.out.println(e);
			if ( e.equals("789") ) {  //①
				set.remove(e);
			}
		}
	}
}
輸出結果爲:
123
456
789
       上面程序中嘗試了使用Iterator遍歷TreeSet集合時,直接調用Set的remove()方法刪除指定的集合元素。運行上面程序,發現該程序完全可以正常結束,並未引發任何異常。
       對於TreeSet、HashSet等Set集合而言,當使用Iterator遍歷時,如果正在遍歷最後一個元素,那麼使用Set集合的remove()方法刪除集合的任意元素並不會引發ConcurrentModificationException異常,當正在遍歷其他元素時刪除集合的任意元素都引發異常。也就是說,如果將程序中的①行代碼改爲等於其他元素,就會引發ConcurrentModificationException異常。

       爲何使用Iterator遍歷List集合的倒數第二個元素時,直接使用List集合的remove()方法刪除List集合的倒數第二個元素沒有引發異常呢?關鍵在於List集合對應的Iterator實現類(Itr)的hasNext()方法。
//Iterator實現類(Itr)源代碼
public boolean hasNext() {
    return cursor != size;
}
       對於Itr遍歷器而言,判斷是否還有下一個元素的標準是:如果下一步即將訪問的元素的索引不等於集合的大小,返回true,否則返回false。當程序使用Iterator遍歷List集合的倒數第二個元素時,下一步即將訪問的元素的索引爲size()-1。如果此時通過List刪除集合的任意一個元素,則將導致集合的size()變爲size()-1,這將導致hasNext()方法返回false。也就是說,遍歷提前結束,Iterator不會訪問List集合的最後一個元素。
       類似地,對於Set集合而言,如果當前正在遍歷集合的最後一個元素,也就是集合遍歷操作已經完成,此時刪除Set集合的任意元素都將不會引發異常。



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