zoukankan      html  css  js  c++  java
  • Java 迭代器理解

    1.Iterator(迭代器)

    作为一种设计模式,迭代器可以用于遍历一个对象,对于这个对象的底层结构不必去了解

    java中的Iterator一般称为“轻量级”对象,创建它的代价是比较小的。这里笔者不会去考究迭代器这种设计模式,仅在JDK代码层面上谈谈迭代器的时候以及使用迭代器的好处。

    2.Iterator 详解

       Iterator是作为一个接口存在的,它定义了迭代器所具有的功能。这里我们就以Iterator接口来看,不考虑起子类ListIterator。其源码如下:

    1 package java.util;
    2 public interface Iterator<E> {
    3     boolean hasNext();
    4     E next();
    5     void remove();
    6 }

    对于这三个方法所实现的功能,字面意义就是了。不过貌似对迭代器的工作“过程”还是迷雾,接下来以一个实际例子来看。

         

     1 public class test_util_1 {
     2 
     3     public static void main(String[] args) {
     4         List<String> list = new ArrayList<String>();
     5         list.add("TEST1");
     6         list.add("TEST2");
     7         list.add("TEST3");
     8         list.add("TEST4");
     9         list.add("TEST6");
    10         list.add("TEST5");
    11         Iterator<String> it = list.iterator();
    12         while (it.hasNext()) {
    13             System.out.println(it.next());
    14         }
    15     }
    16 }

    执行结果:

    TEST1
    TEST2
    TEST3
    TEST4
    TEST6
    TEST5

    这里的it更像是“游标”,不过这游标具体做了啥,还得通过 list.iterator()好好看看。通过源码了解到该方法产生了一个实现Iterator接口的对象。

     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     }

    对于上述的代码不难看懂,有点疑惑的是int expectedModCount = modCount;这句代码

    其实这是集合迭代中的一种“快速失败”机制,这种机制提供迭代过程中集合的安全性。阅读源码就可以知道ArrayList中存在modCount对象,增删操作都会使modCount++,通过两者的对比迭代器可以快速的知道迭代过程中是否存在list.add()类似的操作,存在的话快速失败!

    以一个实际的例子来看,简单的修改下上述代码。   

    1 while(it.hasNext())
    2 {
    3     System.out.println(it.next());
    4     list.add("test");
    5 }

    这就会抛出一个下面的异常,迭代终止。

    对于快速失败机制以前文章中有总结,现摘录过来:    

    Fail-Fast(快速失败)机制

          仔细观察上述的各个方法,在源码中就会发现一个特别的属性modCount,API解释如下:

    The number of times this list has been structurally modified. Structural modifications are those that change the size of the list, or otherwise perturb it in such a fashion that iterations in progress may yield incorrect results.

    记录修改此列表的次数:包括改变列表的结构,改变列表的大小,打乱列表的顺序等使正在进行迭代产生错误的结果。

    Tips:仅仅设置元素的值并不是结构的修改,ArrayList是线程不安全的,如果在使用迭代器的过程中有其他的线程修改了List就会抛出ConcurrentModificationException,这就是Fail-Fast机制。   

    那么快速失败究竟是个什么意思呢?

    在ArrayList类创建迭代器之后,除非通过迭代器自身remove或add对列表结构进行修改,否则在其他线程中以任何形式对列表进行修改,迭代器马上会抛出异常,快速失败。

    迭代器的好处

    通过上述我们明白了迭代是到底是个什么,迭代器的使用也十分的简单。现在简要的总结下使用迭代器的好处吧。

    1、迭代器可以提供统一的迭代方式。

    2、迭代器也可以在对客户端透明的情况下,提供各种不同的迭代方式。

    3、迭代器提供一种快速失败机制,防止多线程下迭代的不安全操作。

    不过对于第三点尚需注意的是:就像上述事例代码一样,我们不能保证迭代过程中出现“快速失败”的都是因为同步造成的,因此为了保证迭代操作的正确性而去依赖此类异常是错误的!

  • 相关阅读:
    boost::asio在VS2008下的编译错误
    Java集合框架——接口
    ACM POJ 3981 字符串替换(简单题)
    ACM HDU 1042 N!(高精度计算阶乘)
    OneTwoThree (Uva)
    ACM POJ 3979 分数加减法(水题)
    ACM HDU 4004 The Frog's Games(2011ACM大连赛区第四题)
    Hexadecimal View (2011ACM亚洲大连赛区现场赛D题)
    ACM HDU 4002 Find the maximum(2011年大连赛区网络赛第二题)
    ACM HDU 4001 To Miss Our Children Time (2011ACM大连赛区网络赛)
  • 原文地址:https://www.cnblogs.com/xingele0917/p/3689345.html
Copyright © 2011-2022 走看看