常见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 hashSet = new HashSet<>();
		System.out.println("HashSet的Iterator:" + hashSet.iterator());
		
		LinkedHashSet linkedHashSet = new LinkedHashSet<>();
		System.out.println("LinkedHashSet的Iterator:" + linkedHashSet.iterator());
		
		TreeSet treeSet = new TreeSet<>();
		System.out.println("TreeSet的Iterator:" + treeSet.iterator());
		
		EnumSet enumSet = EnumSet.allOf(Sex.class);
		System.out.println("EnumSet的Iterator:" + enumSet.iterator());
		
		ArrayList arrayList = new ArrayList<>();
		System.out.println("ArrayList的Iterator:" + arrayList.iterator());
		
		Vector vector = new Vector<>();
		System.out.println("Vector的Iterator:" + vector.iterator());
		
		LinkedList linkedList = new LinkedList<>();
		System.out.println("LinkedList的Iterator:" + linkedList.iterator());
		
		ArrayDeque 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 list = new ArrayList<>();
		list.add("123");
		list.add("456");
		list.add("789");
		for ( Iterator 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 set = new TreeSet<>();
		set.add("123");
		set.add("456");
		set.add("789");
		for ( Iterator 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集合的任意元素都将不会引发异常。



你可能感兴趣的:(Java学习,java,内存,内存管理,程序员,编程语言)