迭代器

  在软构实验一的实现中,我初次接触到了迭代器,感觉这是一种非常新的遍历方式,于是又在网上查阅了不少资料,更加充分的了解了迭代器

  可以直接作用于for循环的数据类型有以下几种:

    一类是集合数据类型,如listtupledictsetstr等;

    一类是generator,包括生成器和带yield的generator function。

    这些可以直接作用于for循环的对象统称为可迭代对象:Iterable

    可以使用isinstance()判断一个对象是否是Iterable对象

j而ava Iterator(迭代器)不是一个集合,它是一种用于访问集合的方法,用来迭代hashset,arreyset等类型的集合。

Iterator 是 Java 迭代器最简单的实现,ListIterator 是 Collection API 中的接口, 它扩展了 Iterator 接口。

 

 

迭代器 it 的两个基本操作是 next 、hasNext 和 remove。

调用 it.next() 会返回迭代器的下一个元素,并且更新迭代器的状态。

调用 it.hasNext() 用于检测集合中是否还有元素。

调用 it.remove() 将迭代器返回的元素删除。

下面插入一段迭代器迭代的示例

 1 // 引入 ArrayList 和 Iterator 类
 2 import java.util.ArrayList;
 3 import java.util.Iterator;
 4 
 5 public class RunoobTest {
 6     public static void main(String[] args) {
 7 
 8         // 创建集合
 9         ArrayList<String> sites = new ArrayList<String>();
10         sites.add("Google");
11         sites.add("Runoob");
12         sites.add("Taobao");
13         sites.add("Zhihu");
14 
15         // 获取迭代器
16         Iterator<String> it = sites.iterator();
17 
18         // 输出集合中的所有元素
19         while(it.hasNext()) {
20             System.out.println(it.next());
21         }
22     }
23 }

可以看到迭代器可以很方便的对各种集合类进行迭代,而且操作都大体相同

在使用Iterator的时候禁止对所遍历的容器进行改变其大小结构的操作。例如: 在使用Iterator进行迭代时,如果对集合进行了add、remove操作就会出现ConcurrentModificationException异常。然而使用lterator.remove()却没有任何问题,其中原因就在于迭代器的实现上

 1 private class Itr implements Iterator<E> {
 2         int cursor;       // index of next element to return
 3         int lastRet = -1; // index of last element returned; -1 if no such
 4         int expectedModCount = modCount;
 5 
 6         public boolean hasNext() {
 7             return cursor != size;
 8         }
 9 
10         @SuppressWarnings("unchecked")
11         public E next() {
12             checkForComodification();
13             int i = cursor;
14             if (i >= size)
15                 throw new NoSuchElementException();
16             Object[] elementData = ArrayList.this.elementData;
17             if (i >= elementData.length)
18                 throw new ConcurrentModificationException();
19             cursor = i + 1;
20             return (E) elementData[lastRet = i];
21         }
22 
23         public void remove() {
24             if (lastRet < 0)
25                 throw new IllegalStateException();
26             checkForComodification();
27 
28             try {
29                 ArrayList.this.remove(lastRet);
30                 cursor = lastRet;
31                 lastRet = -1;
32                 expectedModCount = modCount;
33             } catch (IndexOutOfBoundsException ex) {
34                 throw new ConcurrentModificationException();
35             }
36         }
37 
38         final void checkForComodification() {
39             if (modCount != expectedModCount)
40                 throw new ConcurrentModificationException();
41         }
42     }

通过查看源码发现原来检查并抛出异常的是checkForComodification()方法。在ArrayList中modCount是当前集合的版本号,每次修改(增、删)集合都会加1;expectedModCount是当前迭代器的版本号,在迭代器实例化时初始化为modCount。

我们看到在checkForComodification()方法中就是在验证modCount的值和expectedModCount的值是否相等,所以当调用了ArrayList.add()或者ArrayList.remove()时,只更新了modCount的状态,而迭代器中的expectedModCount未同步,因此才会导致再次调用Iterator.next()方法时抛出异常。但是为什么使用Iterator.remove()就没有问题呢?通过源码的第32行发现,在Iterator的remove()中同步了expectedModCount的值,所以当你下次再调用next()的时候,检查不会抛出异常。

 

posted @ 2022-06-09 10:44  HITyfj  阅读(47)  评论(0)    收藏  举报