在前面大致讲解了Collection这个根接口的知识,让我们知道Collection接口是List、Set和Queue接口的父接口,该接
口里定义的方法既可用于操作Set集合,也可用于操作List和Queue集合。关于Collection下的子接口和实现类在后面
会讲解到,今天我们来看下Iterator接口,如下程序:
public interface Collection<E> extends Iterable<E>
Collection这个根接口继承了Iterable接口,我们来看下Iterable接口中定义的方法:
Iterator<T> iterator();
Iterator接口也是Java集合框架的成员,只是它与Collection系列、Map系列的集合不一样,Collection系列集合、Map
系列集合主要用于盛装其他对象,而Iterator主要用于遍历Collection集合中的元素,Iterator对象也被称为迭代
器。Iterator接口隐藏了各种Collection实现类的底层细节,向应用程序提供了遍历Collection集合元素的统一编程接
口。
关于Iterator接口定义的方法:
boolean hasNext();
hasNext的用法:如果被迭代的集合元素还没有遍历完,返回true。
E next();
next的用法:返回集合里的下一个元素。
default void remove() { throw new UnsupportedOperationException("remove"); }
remove的用法:删除集合里上一次next方法返回的元素。如果迭代器不支持remove操作的话,就会抛出上面的
UnsupportedOperationException异常。
Iterator的用法如下程序:
public class IteratorTest { public static void main(String[] args) { Collection collection=new HashSet(); collection.add("Bill"); collection.add(2); collection.add(true); Iterator iterator=collection.iterator(); while(iterator.hasNext()){ System.out.println(iterator.next()); } } }
关于HashSet在后续讲解时会提到,有一点需记住HashSet是通过Hash算法来存储集合中的元素的。通过Collection接
口中add方法添
加元素,并通过被迭代的集合来获取Iterator对象,最后分别输出集合的元素。
以下是我们常发生的错误:
public class IteratorTest { public static void main(String[] args) { Collection collection=new HashSet(); collection.add("Bill"); collection.add("Jack"); collection.add("Sun"); Iterator iterator=collection.iterator(); while(iterator.hasNext()){ String name=(String)iterator.next(); System.out.println(name); if(name.equals("Jack")){ collection.remove(name); } } } }
输出:
Bill
Jack
Exception in thread "main" java.util.ConcurrentModificationException
at java.util.HashMap$HashIterator.nextNode(HashMap.java:1429)
at java.util.HashMap$KeyIterator.next(HashMap.java:1453)
at code2.IteratorTest.main(IteratorTest.java:27)
以上程序在进行迭代时,删除第二个元素“Jack”时引发异常,我们来看看ConcurrentModificationException引发异常
的真正原因:
当方法检测到对象的并发修改,但不允许这种修改时,抛出此异常。
例如,某个线程在 Collection 上进行迭代时,通常不允许另一个线性修改该 Collection。通常在这些情况下,迭代的
结果是不确定的。如果检测到这种行为,一些迭代器实现(包括 JRE 提供的所有通用 collection 实现)可能选择抛
出此异常。执行该操作的迭代器称为快速失败 迭代器,因为迭代器很快就完全失败,而不会冒着在将来某个时间任
意发生不确定行为的风险。
注意,此异常不会始终指出对象已经由不同 线程并发修改。如果单线程发出违反对象协定的方法调用序列,则该对
象可能抛出此异常。例如,如果线程使用快速失败迭代器在 collection 上迭代时直接修改该 collection,则迭代器将
抛出此异常。
注意,迭代器的快速失败行为无法得到保证,因为一般来说,不可能对是否出现不同步并发修改做出任何硬性保
证。快速失败操作会尽最大努力抛出 ConcurrentModificationException。因此,为提高此类操作的正确性而编写一个
依赖于此异常的程序是错误的做法,正确做法是:ConcurrentModificationException 应该仅用于检测 bug。
OK,如果我们改成删除第一个元素“Bill”呢?
public class IteratorTest { public static void main(String[] args) { Collection collection=new HashSet(); collection.add("Bill"); collection.add("Jack"); collection.add("Sun"); Iterator iterator=collection.iterator(); while(iterator.hasNext()){ String name=(String)iterator.next(); System.out.println(name); if(name.equals("Bill")){ collection.remove(name); } } } }
输出:
Bill Exception in thread "main" java.util.ConcurrentModificationException at java.util.HashMap$HashIterator.nextNode(HashMap.java:1429) at java.util.HashMap$KeyIterator.next(HashMap.java:1453) at code2.IteratorTest.main(IteratorTest.java:27)
好吧,又引发异常了,那改成删除最后一个元素呢?
public class IteratorTest { public static void main(String[] args) { Collection collection=new HashSet(); collection.add("Bill"); collection.add("Jack"); collection.add("Sun"); Iterator iterator=collection.iterator(); while(iterator.hasNext()){ String name=(String)iterator.next(); System.out.println(name); if(name.equals("Sun")){ collection.remove(name); } } } }
输出:
Bill
Jack
Sun
以上程序终于删除了最后一个元素。现在我们终于知道,当我们使用Iterator迭代访问Collection集合元素时,
Collection集合里的元素不能被改变,只有通过Iterator的remove方法删除上一次next方法返回的集合元素才可以,否
则将会引发ConcurrentModificationException异常,以上程序,是在遍历最后一个元素后删除最后的元素,其实在使
用next方法遍历到最后的元素后,如果再调用hashNext就会返回false,也就是说遍历到最后一个元素后,迭代就已经
完毕了,也就不存在当使用Iterator迭代访问Collection集合元素时,对集合元素进行改变了。
转载请注明出处:http://blog.csdn.net/hai_qing_xu_kong/article/details/44001581 情绪控_