基础篇-Iterator和Iterable的区别以及使用

 我们都知道,在使用除Map类集合得有序集合时,都可以使用迭代器进行遍历。那么什么是迭代器?如何使用呢?

1、什么是迭代器

官方说法还是蛮正规得:迭代器(iterator)是一种对象,它能够用来遍历标准模板库容器中的部分或全部元素,每个迭代器对象代表容器中的确定的地址。迭代器修改了常规指针的接口,所谓迭代器是一种概念上的抽象:那些行为上像迭代器的东西都可以叫做迭代器。然而迭代器有很多不同的能力,它可以把抽象容器和通用算法有机的统一起来。

不过个人理解所谓迭代器不就是把遍历容器元素得不同规则都包含在一起嘛,每种容器有自己得遍历方式,而迭代器只是将其抽象出来。我们都知道集合容器存储元素的实现是比较复杂得,毕竟底层原理什么哈西啊、链表啊数据最优存储啊,都是复杂得一匹,而集合类已经帮我们这么多了,像遍历这种事情可定不能再依赖于集合类啦,所以呢想要遍历就需要我们自己实现,但是呢开发者又担心让使用者自己去实现,又会让容器的内部袭击暴露无遗,所以呢就在客户访问类与容器体之间插入一个第三者(迭代器),知识点来啦,这也是迭代器模式哟!

好了,解释完定义我们就开始看看如何使用吧!

首先明确一下:

Iterator是java.util包下得接口

package java.util;


public interface Iterator
{

    public abstract boolean hasNext();

    public abstract Object next();

    public abstract void remove();
}

Iterable是java.lang下得接口

package java.lang;

import java.util.Iterator;

// Referenced classes of package java.lang:
//            Object

public interface Iterable
{

    public abstract Iterator iterator();
}

首先我们都知道,集合类和数组都是遍历这玩意得常用之处,那么就来看一下实例:

import java.util.ArrayList;
import java.util.Iterator;
import java.util.List;

public class IteratorDemo {
	public static void main(String[] args) {
		List<String> list = new ArrayList<String>();
		list.add("A");
		list.add("B");
		list.add("C");
		Iterator it = list.iterator();
		while(it.hasNext()){
			System.out.println(it.next());
		}	
	}	
}

上面得list集合调用iterator()方法返回一个迭代器实例it。

那么这个接口方法是如何定义的呢,这就要找顶层啦。

我们知道ArrayList实现了List接口,而List又继承了java.util.Collection接口,而Collection又继承了Iterable接口,而该接口只有一个方法,就是: public abstract Iterator iterator();一个返回迭代器的方法,因此得出结论:实现了iterator接口就可以实现使用迭代器。这里特别说明一下反过来能使用迭代器的未必就一定实现了该接口,例如数组(具体原因尚不明确,知道的小伙伴请留言)。还有提到一下Collection接口的作用是给有序集合的接口的公共方法的再一次抽象。因为Collection实现了Iterable接口,所以有序集合都可以使用迭代器。

好了,既然规定可以使用迭代器了,那自己定义迭代器迭代规则吧,说白了就是是按Iterator定义的三个方法,我们看ArrayList是如何实现的吧:

private class Itr
        implements Iterator
    {

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

        public Object next()
        {
            checkForComodification();
            try
            {
                int i = cursor;
                Object obj = get(i);
                lastRet = i;
                cursor = i + 1;
                return obj;
            }
            catch(IndexOutOfBoundsException indexoutofboundsexception)
            {
                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 indexoutofboundsexception)
            {
                throw new ConcurrentModificationException();
            }
        }

        final void checkForComodification()
        {
            if(modCount != expectedModCount)
                throw new ConcurrentModificationException();
            else
                return;
        }

        int cursor;
        int lastRet;
        int expectedModCount;
        final AbstractList this$0;

        private Itr()
        {
            this$0 = AbstractList.this;
            super();
            cursor = 0;
            lastRet = -1;
            expectedModCount = modCount;
        }

    }

上面的代码是Arraylist类中的内部类,他实现了迭代器规则。因为大多数的迭代器规则都不需要我们自己开发,因为JDK已经帮助我们做好了,因此迭代器模式只是作为学习使用。

不过学以致用,我们自己实现一个迭代器,让自己的类能够被迭代(foreach的原理就是迭代器,因此有种说法就是所有实现Iterable的都来可以使用foreach来迭代)

/**
 * Iterable接口:包含一个能产生Iterator的Iterator()方法,并且Iteable接口被foreach用来在序列中移动,因此只要实现该接口,都可以将其用在foreach语句中
 * */
public class IterableDemo implements Iterable<String>{
	String[] str = ("And that is how we know the Earth to be banana-shaped.").split(" ");
	public static void main(String[] args) {
		for (String string : new IterableDemo()) {
			System.out.println(string);
		}
	}
	@Override
	public Iterator<String> iterator() {

		return new Iterator<String>(){
			private int index = 0;
			
			@Override
			public boolean hasNext(){
				return index < str.length;
			}
			
			@Override
			public String next() {
				return str[index++];
			}
			@Override
			public void remove() {
				throw new UnsupportedOperationException();
			}		
			
		};
	}

}

打印结果:

And
that
is
how
we
know
the
Earth
to
be
banana-shaped.

上面的代码:

第一步:实现Iterable接口,只不过加了String泛型

第二部:实现Iterable的方法,这里使用匿名内部类创建了Iterator实现对象

第三部:使用Foreach循环遍历

下面证明一下数组不是Iterable类型的

public class IteratorDemo {
	public static void main(String[] args) {
		//使用结合作为参数
		test(Arrays.asList("A","B","C"));
		//直接将数组作为参数
		String[] strArr = {"D","E","F"};
		test(strArr);
	}
	public static <T> void test(Iterable<T> it){
		for (T t : it) {
			System.out.println(t);
		}
	}
}

将数组作为参数时,编译期即报错。

Exception in thread "main" java.lang.Error: Unresolved compilation problem: 
	The method test(Iterable<T>) in the type IteratorDemo is not applicable for the arguments (String[])

	at collectionDemo.IteratorDemo.main(IteratorDemo.java:11)

一次数组不存在自动转换。尝试把数组当作一个Iterable参数传递会导致失败。

猜你喜欢

转载自blog.csdn.net/ysj4428/article/details/81297329
今日推荐