关闭

Iterable接口和Iterator迭代器

标签: IterableIterator
368人阅读 评论(0) 收藏 举报
分类:

iterator接口定义如下

public interface Iterator<E> {

    boolean hasNext();
    E next();
    void remove();
}
该接口仅仅包含了三个函数,hasNext()和next()方法在我们常用的集合遍历中出现。 
三个函数的作用:
使用next()获得序列中的下一个元素。
使用hasNext()检查序列中是否还有元素。
使用remove()将迭代器新返回的元素删除。remove()方法必须和next方法一起使用。

对于已经实现了iterator接口的集合,一般遍历集合的写法为 如,我们常用的list集合,list集合已经实现了iterator接口 :
方法一:

list l = new ArrayList();
 l.add("aa");
 l.add("bb");
 l.add("cc");

  for (Iterator iter = l.iterator(); iter.hasNext();) {
  String str = (String)iter.next();
  System.out.println(str);
 }

方法二:

Iterator iter = l.iterator();
 while(iter.hasNext()){
  String str = (String) iter.next();
  System.out.println(str);
 }
这里我们查看 Abstractlist源码,中间有关于iterator实现细节,上面的iter实际上是多态,调用的其实是list的抽象Abstractlist类中的iterator方法:
private class Itr implements Iterator<E> {

        int cursor = 0;
        int lastRet = -1;
        int expectedModCount = modCount;

        public boolean hasNext() {
            return cursor != size();
        }

        public E next() {
            checkForComodification();
            try {
                int i = cursor;
                E next = get(i);
                lastRet = i;
                cursor = i + 1;
                return next;
            } catch (IndexOutOfBoundsException e) {
                checkForComodification();
                throw new NoSuchElementException();
            }
        }

        public void remove() {
            if (lastRet < 0)
                throw new IllegalStateException();
            checkForComodification();

            try {
                AbstractList.this.remove(lastRet);
                if (lastRet < cursor)
                    cursor--;
                lastRet = -1;
                expectedModCount = modCount;
            } catch (IndexOutOfBoundsException e) {
                throw new ConcurrentModificationException();
            }
        }

        final void checkForComodification() {
            if (modCount != expectedModCount)
                throw new ConcurrentModificationException();
        }
    }
通过源码,我们可以更加清晰的看出iterator三个函数的实现机制,细心的读者可能会发现,move()方法中 expectedModCount = modCount;有这样一个表达式。这其实是list中的快速失败机制。modcount在arraylist中的增删会使得其值变化,而expectedModcount是在遍历中维持的值,如果这两者不相等,表示在遍历的时候,出现了写操作。导致了数据不一致。 

Iterable接口定义如下

public interface Iterable<T> {

    /**
     * Returns an iterator over a set of elements of type T.
     *
     * @return an Iterator.
     */
    Iterator<T> iterator();
}
Java SE5引入了Iterable接口,该接口包含一个能够产生Iterator的iterator()方法,并且Iterable接口被foreach用来在序列中移动。因此你创建了任何实现Iterable的自定义类,都可以将它用于foreach语句中。
Iterable的主要作用为:实现Iterable接口来实现适用于foreach遍历的自定义类。
import java.util.Iterator;

public class IterablerClass<T> implements Iterable<T>{
    private T[] array = null;

    public IterablerClass(T[] t){
        this.array = t ;
    }
    @Override
    public Iterator<T> iterator() {
        // TODO Auto-generated method stub
        return new Iterator<T>() {
            private Integer index = 0;
            @Override
            public boolean hasNext() {
                // TODO Auto-generated method stub
                return index<array.length;
            }

            @Override
            public T next() {
                // TODO Auto-generated method stub
                return array[index++];
            }

            @Override
            public void remove() {
                // TODO Auto-generated method stub
            }
        };
    }
public static void main(String[] args) {
IterablerClass<String> iterablerClass = new IterablerClass<String>(new String[]{"hello","world","today","happy","sorrow"});
    for(String s:iterablerClass){
            System.out.print(s+" ");
        }

    }
}
用Iterator模式实现遍历集合 
        Iterator模式是用于遍历集合类的标准访问方法。它可以把访问逻辑从不同类型的集合类中抽象出来,从而避免向客户端暴露集合的内部结构。
        例如,如果没有使用Iterator,遍历一个数组的方法是使用索引: for(int i=0; i<array.size(); i++) { ... get(i) ... }
        而访问一个链表(LinkedList)又必须使用while循环: while((e=e.next())!=null) { ... e.data() ... } 
        以上两种方法客户端都必须事先知道集合的内部结构,访问代码和集合本身是紧耦合,无法将访问逻辑从集合类和客户端代码中分离出来,每一种集合对应一种遍历方法,客户端代码无法复用。
        更恐怖的是,如果以后需要把ArrayList更换为LinkedList,则原来的客户端代码必须全部重写。
        解决以上问题,Iterator模式总是用同一种逻辑来遍历集合: for(Iterator it = c.iterater(); it.hasNext(); ) { ... } 
为什么一定要去实现Iterable这个接口呢?为什么不直接实现Iterator接口呢?
        看一下JDK中的集合类,比如List一族或者Set一族,都是实现了Iterable接口,但并不直接实现Iterator接口。 仔细想一下这么做是有道理的。
        因为Iterator接口的核心方法next()或者hasNext() 是依赖于迭代器的当前迭代位置的。 如果Collection直接实现Iterator接口,势必导致集合对象中包含当前迭代位置的数据(指针)。 当集合在不同方法间被传递时,由于当前迭代位置不可预置,那么next()方法的结果会变成不可预知。 除非再为Iterator接口添加一个reset()方法,用来重置当前迭代位置。 但即时这样,Collection也只能同时存在一个当前迭代位置。 而Iterable则不然,每次调用都会返回一个从头开始计数的迭代器。 多个迭代器是互不干扰的。

0
0

查看评论
* 以上用户言论只代表其个人观点,不代表CSDN网站的观点或立场
    个人资料
    • 访问:202988次
    • 积分:3167
    • 等级:
    • 排名:第12043名
    • 原创:140篇
    • 转载:34篇
    • 译文:0篇
    • 评论:20条
    最新评论