Java学习笔记24

时间:2023-02-26 13:09:07

在前面大致讲解了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接口定义的方法:

Java学习笔记24


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  情绪控_