3、Iterator、Iterable详解

本文详细介绍了Java中的Iterator和Iterable接口,包括如何判断迭代器位置、移动、删除元素及其影响,以及如何防止多个迭代器之间的相互影响。此外,还讨论了ListIterator的特性和与普通Iterator的区别,如双向遍历和元素的添加、修改功能。

Iterator概述

如何判断当前迭代器的位置,及如何移动?

  1. java的迭代器是无法将随机访问的,也就是说不可以根据输入的数字来跳转到指定的位置,迭代器到达任何一个位置都需要经过next或者可能存在的previous方法实现,只能一个一个的移动。
  2. 是迭代器并不是指向一个元素的,而是指向元素之间的。迭代器初始化之后再0号元素之前,迭代到尾之后是在最后一个元素之后,期间任何一点都是指向两个元素之间的位置。每次调用迭代器之前通常都需要进行查询即使用hasNext方法确定是否已经迭代到尾,如果迭代到尾就返回false。如果已经迭代到尾还强行的运行next则会抛出异常。

如何对迭代的元素进行删除,及删除后的影响?

  1. 由于迭代器没有办法进行随机访问,因此如果需要删除元素也只能删除刚刚跳过的元素。这样也导致每次remove之前必定有一个next。如果连续进行两次remove则会抛出异常。因为并不知道删除的元素是哪一个。

如何防止多个迭代器之间的相互影响?

在使用迭代器的时候,如果一个迭代器正在迭代器另一个迭代器修改了元素这样可能会导致很严重的问题。java采用一个计数器来保证不会有两个迭代器同时修改这个对象,具体的部分等到实现来说明。通常来说如果迭代器在进行访问时,另一个迭代器结构性的修改了对象,则正在访问的迭代器会抛出异常。但是如果是多个迭代器只进行读操作就可以。当然也可以自定义的修改成多个读迭代器和一个写迭代器。这样可以提高访问速率。

Iterable

用于生成迭代器,因此对于需要迭代的集合需要提供一个生成迭代器的方法

该接口只有一个需要实现的方法 Iterator<T> iterator();生成一个迭代器对象

public interface Iterable<T> {

    Iterator<T> iterator();

    default void forEach(Consumer<? super T> action) {
        Objects.requireNonNull(action);
        for (T t : this) {
            action.accept(t);
        }
    }


    default Spliterator<T> spliterator() {
        return Spliterators.spliteratorUnknownSize(iterator(), 0);
    }
}

因此collection接口继承了Iterable接口

Iterator

Iterator接口是迭代器,真正实现集合迭代的接口,不同集合的迭代方式不同,是应为有不同的iterator实现。

public interface Iterator<E> {

    boolean hasNext();

    E next();


    default void remove() {
        throw new UnsupportedOperationException("remove");
    }

    default void forEachRemaining(Consumer<? super E> action) {
        Objects.requireNonNull(action);
        while (hasNext())
            action.accept(next());
    }
}

对于iterator必须要实现的方法有2个,其中的remove()方法可以不实现,但是调用的时候出错。(此处依赖于java8的新特性)

一开始迭代器在所有元素的左边,调用next()之后,迭代器移到第一个和第二个元素之间,next()方法返回迭代器刚刚经过的元素。

hasNext()若返回True,则表明接下来还有元素,迭代器不在尾部。

remove()方法必须和next方法一起使用,功能是去除刚刚next方法返回的元素。(可以不实现)

forEachRemaining,可以专门使用Lambda表达式进行遍历,以完成一些强大的功能。

元素访问的顺序,取决于集合的类型,list从0开是,每访问一次迭代值+1,对于set等,会按照某种随机的顺序访问,虽然保证都可以访问到,但不保证顺序。

ListIterator迭代器

ListIterator的定义

public interface ListIterator<E> extends Iterator<E> {
    //如果迭代器指向位置后面还有元素,则返回 true,否则返回false
    boolean hasNext();
    //返回集合中Iterator指向位置后面的元素
    E next();
//删除集合中Iterator指向位置后面的元素
    void remove();
  // ListIterator迭代器包含的特有的方法
    //如果以逆向遍历列表,列表迭代器前面还有元素,则返回 true,否则返回false
    boolean hasPrevious();
//返回列表中ListIterator指向位置前面的元素
    E previous();
//返回列表中ListIterator所需位置后面元素的索引
    int nextIndex();
//返回列表中ListIterator所需位置前面元素的索引
    int previousIndex();
//从列表中将next()或previous()返回的最后一个元素返回的最后一个元素更改为指定元素e
    void set(E e);
//将指定的元素插入列表,插入位置为迭代器当前位置之前
    void add(E e);
}

相同点

都是迭代器,当需要对集合中元素进行遍历不需要干涉其遍历过程时,这两种迭代器都可以使用。

不同点

  1. 使用范围不同,Iterator可以应用于所有的集合,Set、List和Map和这些集合的子类型。而ListIterator只能用于List及其子类型。
  2. ListIterator有add方法,可以向List中添加对象,而Iterator不能。
  3. ListIterator和Iterator都有hasNext()和next()方法,可以实现顺序向后遍历,但是ListIterator有hasPrevious()和previous()方法,可以实现逆向(顺序向前)遍历。Iterator不可以。
  4. ListIterator可以定位当前索引的位置,nextIndex()和previousIndex()可以实现。Iterator没有此功能。
  5. 都可实现删除操作,但是ListIterator可以实现对象的修改,set()方法可以实现。Iterator仅能遍历,不能修改。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值