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
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
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
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集合的任意元素都将不会引发异常。