Files
notes_estom/Java/03Java集合类/07 Iterable&Ieterator.md
yinkanglong cc62258411 java
2023-10-21 09:55:22 +08:00

5.9 KiB
Raw Blame History

Iterator Iterable ListIterator

1 Iterator

所有Java集合类都提供iterator()方法该方法返回Iterator的实例以遍历该集合中的元素。

public interface Iterator<E> {
    boolean hasNext();
    E next();
    void remove();
}

提供的API接口含义如下

  • hasNext():判断集合中是否存在下一个对象
  • next():返回集合中的下一个对象,并将访问指针移动一位
  • remove():删除集合中调用next()方法返回的对象.每次调用next只能调用一次此方法。

在早期,遍历集合的方式只有一种,通过Iterator迭代器操作

List<Integer> list = new ArrayList<>();
list.add(1);
list.add(2);
list.add(3);
Iterator iter = list.iterator();
while (iter.hasNext()) {
    Integer next = iter.next();
    System.out.println(next);
    if (next == 2) { iter.remove(); }
}

2 Iterable

public interface Iterable<T> {
    Iterator<T> iterator();
    // JDK 1.8
    default void forEach(Consumer<? super T> action) {
        Objects.requireNonNull(action);
        for (T t : this) {
            action.accept(t);
        }
    }
}

可以看到Iterable接口里面提供了Iterator接口,所以实现了Iterable接口的集合依旧可以使用迭代器遍历和操作集合中的对象;

而在 JDK 1.8中,Iterable提供了一个新的方法forEach(),它允许使用增强 for 循环遍历对象。

List<Integer> list = new ArrayList<>();
for (Integer num : list) {
    System.out.println(num);
}

我们通过命令:javap -c反编译上面的这段代码后,发现它只是 Java 中的一个语法糖,本质上还是调用Iterator去遍历。

翻译成代码,就和一开始的Iterator迭代器遍历方式基本相同了。

Iterator iter = list.iterator();
while (iter.hasNext()) {
    Integer num = iter.next();
    System.out.println(num);
}

还有更深层次的探讨:为什么要设计两个接口IterableIterator,而不是保留其中一个就可以了。

简单讲解:Iterator的保留可以让子类去实现自己的迭代器,而Iterable接口更加关注于for-each的增强语法。具体可参考:Java中的Iterable与Iterator详解

3 Iterator 和Iterable

关于IteratorIterable的讲解告一段落,下面来总结一下它们的重点:

  1. Iterator是提供集合操作内部对象的一个迭代器,它可以遍历、移除对象,且只能够单向移动
  2. Iterable是对Iterator的封装,在JDK 1.8时,实现了Iterable接口的集合可以使用增强 for 循环遍历集合对象,我们通过反编译后发现底层还是使用Iterator迭代器进行遍历

等等,这一章还没完,还有一个ListIterator。它继承 Iterator 接口,在遍历List集合时可以从任意索引下标开始遍历,而且支持双向遍历

ListIterator 存在于 List 集合之中,通过调用方法可以返回起始下标index的迭代器

List<Integer> list = new ArrayList<>();
// 返回下标为0的迭代器
ListIterator<Integer> listIter1 = list.listIterator(); 
// 返回下标为5的迭代器
ListIterator<Integer> listIter2 = list.listIterator(5); 

ListIterator 中有几个重要方法,大多数方法与 Iterator 中定义的含义相同,但是比 Iterator 强大的地方是可以在任意一个下标位置返回该迭代器,且可以实现双向遍历

public interface ListIterator<E> extends Iterator<E> {
    boolean hasNext();
    E next();
    boolean hasPrevious();
    E previous();
    int nextIndex();
    int previousIndex();
    void remove();
    // 替换当前下标的元素,即访问过的最后一个元素
    void set(E e);
    void add(E e);
}

4 ListIterator

简介

  • ListIterator支持在元素列表上的所有CRUD操作CREATEREADUPDATE和DELETE
  • 与Iterator不同ListIterator是bi-directional 。 它支持正向和反向迭代。
  • 它没有当前元素; 它的光标位置始终位于通过调用previous返回的元素和通过调用next返回的元素之间。

实例

ArrayList<String> list = new ArrayList<>();
         
list.add("A");
list.add("B");
list.add("C");
list.add("D");
list.add("E");
list.add("F");
 
ListIterator<String> listIterator = list.listIterator();
 
System.out.println("Forward iteration");
 
//Forward iterator
while(listIterator.hasNext()) {
    System.out.print(listIterator.next() + ",");
}
 
System.out.println("Backward iteration");
 
//Backward iterator
while(listIterator.hasPrevious()) {
    System.out.print(listIterator.previous() + ",");
}
 
System.out.println("Iteration from specified position");
         
//Start iterating from index 2
listIterator = list.listIterator(2);
 
while(listIterator.hasNext()) {
    System.out.print(listIterator.next() + ",");

主要方法

void add(Object o) 将指定的元素插入列表可选操作)。
boolean hasNext() 如果在向前遍历列表时此列表迭代器包含更多元素则返回true 
boolean hasPrevious() 如果在反向遍历列表时此列表迭代器包含更多元素则返回true 
Object next() 返回列表中的下一个元素并前进光标位置
int nextIndex() 返回元素的索引该元素的索引将由对next的后续调用返回
Object previous() 返回列表中的上一个元素并将光标位置向后移动
int previousIndex() 返回元素的索引该元素的索引将由对next的后续调用返回
void remove() 从列表中移除next或previous返回的最后一个元素可选操作)。
void set(Object o) 将next或previous返回的最后一个元素替换为指定的元素可选操作)。