您的位置:首页 > 博客中心 > 互联网 >

Iterator与Iterable(迭代器模式)

时间:2022-05-11 07:04

1、引言

在Java中,我们可以对List集合进行如下几种方式的遍历:

List list = new ArrayList<>();

// 法一:普通for循环
for (int i = 0; i < list.size(); i++) {
    System.out.print(list.get(i) + ",");
}

//法二:迭代器遍历
Iterator it = list.iterator();
while (it.hasNext()) {
    System.out.print(it.next() + ",");
}

// for each遍历
for (Integer i : list) {
    System.out.print(i + ",");
}

// 后面两种方式涉及到Java中的Iterator和Iterable对象

2、两者关系

看Iterable和Iterator所处包位置,Collection接口必须继承java.lang.Iterable接口。

技术图片

Iterator为Java中的迭代器对象,是能够对List这样的集合进行迭代遍历的底层依赖。

Iterable接口里定义了返回Iterator的方法,相当于对Iterator的封装,同时实现了Iterable接口的类可以支持for each循环。

JDK中 Iterator 接口源码

public interface Iterator {
	boolean hasNext();		// 检查序列中是否还有元素
    
  	E next();	// 获取序列中下一个元素
    
    default void remove() {		// 将迭代器新返回的元素删除
        throw new UnsupportedOperationException("remove");
    }
    
    // 1.8新增的Iterator接口中的默认方法,对集合中*剩余*的元素进行操作,直到元素完毕或者抛出异常;注意为“剩余”,即迭代中还剩余的部分
    default void forEachRemaining(Consumer action) {
        Objects.requireNonNull(action);
        while (hasNext())
            action.accept(next());
    }
}

集合类都实现了这个接口, Iterator 是迭代器最简单的实现,使用Iterator iter = list.iterator()就实现了迭代器(见上面引言的使用)

Iterable接口的源码

public interface Iterable {
    Iterator iterator();		// 方法iterator()返回了一个Iterator对象(各具体类返回的类型也不同)
    
    // 1.8新加的方法,对每个元素执行特有操作,可使用Lambda表达式
    default void forEach(Consumer action) {
        Objects.requireNonNull(action);
        for (T t : this) {
            action.accept(t);
        }
    }
    
    // 1.8新方法,可分割迭代器,用于并行遍历元素
    default Spliterator spliterator() {
        return Spliterators.spliteratorUnknownSize(iterator(), 0);
    }
}

for each实现:为Java语法糖,也是依赖Iterator迭代器,编译器自动转化

for (Integer i : list);
for(Iterator iterator = list.iterator(); iterator.hasNext(); System.out.println(i)){
        i = (Integer)iterator.next();
}

3、为什么这样设计

这里是使用到了设计模式中的迭代器模式

  • 为什么用Iterator实现遍历?(为什么使用迭代器模式)

    • 用于遍历集合类的标准访问方法,它可以把访问逻辑从不同类型的集合类中抽象出来,从而避免向客户端暴露集合的内部结构(其他索引遍历需要知道集合内部结构,且更换集合时需要重写遍历方法);
    • 支持以不同的方式遍历一个聚合对象;
    • 简化了聚合类;
    • 在同一个聚合上可以有多个遍历;
    • 便于增加迭代器类和新的聚合类。
  • 为什么一定要去实现Iterable这个接口而不直接实现Iterator接口?

    因为next()或者hasNext() 都依赖于迭代器当前的迭代位置,如果Collection直接实现Iterator接口,势必导致集合对象中包含当前迭代位置的数据(指针)。
    当集合在不同方法间被传递时,由于当前迭代位置不可预置,那么next()方法的结果会变成不可预知。
    除非再为Iterator接口添加一个reset()方法,用来重置当前迭代位置。 但这样,Collection也只能同时存在一个当前迭代位置。
    而Iterable则不然,每次调用都会返回一个从头开始计数的迭代器。,使得多个迭代器是互不干扰的。

  • 为什么不直接将hasNext(),next()方法放在Iterable接口中,其他类直接实现就可以了?

    为了使集合类可以有多种遍历方式。

本类排行

今日推荐

热门手游