Java 集合教程

Java 集合:Iterator 接口

Iterator 接口位于 java.util 包中,表示一个能够在 Java 对象集合中一次遍历一个对象的对象,还是 Java 中最古老的对象集合迭代机制之一(Enumerator 比 Iterator 还要古老)。

Iterator 接口提供了一种标准的方法来遍历集合中的元素,而无需关心集合的具体实现方式。使用它可以在不暴露集合内部结构的情况下,对集合中的元素进行访问和操作。

注意,要使用 Iterator,必须从要遍历的集合对象中获取一个 Iterator 实例。获取的 Iterator 会跟踪底层集合中的元素,以确保遍历所有元素。如果在遍历指向的底层集合时修改了该集合(如删除了元素),迭代器通常会检测到,并在下次尝试从迭代器中获取下一个元素时抛出异常。

  

核心方法

Iterator 接口相当简单,核心方法如下:

  • hasNext():检查集合中是否还有下一个元素。如果有,返回 true;否则返回 false。

  • next():返回集合中的下一个元素,并将迭代器的位置向后移动一位。如果没有下一个元素,会抛出 NoSuchElementException 异常。

  • remove():移除迭代器最后返回的元素。该方法只能在每次调用 next() 方法之后调用一次,如果违反此规则,会抛出 IllegalStateException 异常。

  • forEachRemaining():对迭代器中的所有剩余元素进行迭代,并调用 Lambda 表达式,将每个剩余元素作为参数传递给该 Lambda 表达式。

这些方法中的每一个都将在以下部分中详细介绍。

  

获取迭代器(Iterator)

Java 集合 Collection 接口包含一个名为 iterator() 的方法。通过调用 iterator() 方法,可以从给定的集合中获得一个迭代器。

你还可以从许多 Java 集合数据结构(如 List、Set、Map、Queue、Deque 或 Map)中获取迭代器。

下面是几个从各种 Java 集合类型中获取 Java Iterator 的示例:

import java.util.*;

public class Demo {

    public static void main(String[] args) {
        List<String> list = new ArrayList<>();
        list.add("one");
        list.add("two");
        list.add("three");
        // 从 List 获取迭代器
        Iterator<String> iterator = list.iterator();
        while(iterator.hasNext()) { // 遍历迭代器数据
            System.out.println(iterator.next());
        }
        
        System.out.println("=======================");

        Set<String> set = new HashSet<>();
        set.add("one");
        set.add("two");
        set.add("three");
        // 从 Set 获取迭代器
        Iterator<String> iterator2 = set.iterator();
        while(iterator2.hasNext()) { // 遍历迭代器数据
            System.out.println(iterator2.next());
        }
    }

}

运行结果:

one
two
three
=======================
one
two
three

  

迭代器的用法(Iterator)

你可以使用 while 循环遍历 Iterator 中的对象。例如:

import java.util.*;

public class Demo {

    public static void main(String[] args) {
        List<String> list = new ArrayList<>();
        list.add("one");
        list.add("two");
        list.add("three");
      
        Iterator<String> iterator = list.iterator();
        while(iterator.hasNext()) {
            String val = iterator.next();
            System.out.println(val);
        }
    }
    
}

运行结果:

one
two
three

在上述 Java 示例中,有两个方法需要注意:

  • 第一个方法是 hasNext() 方法,如果迭代器包含更多元素,该方法将返回 true,否则,返回 false。

  • 第二个方法是 next() 方法,next() 方法返回迭代器正在迭代的集合的下一个元素。

注意:Iterator 中所含元素的遍历顺序取决于提供 Iterator 的对象。例如,从 List 获取的迭代器将按照 List 内部存储元素的相同顺序遍历 List 中的元素。而从集合获取的迭代器则不能保证集合中元素的确切迭代顺序。

  

迭代期间修改

某些集合不允许在通过迭代器迭代时修改集合。在这种情况下,下一次调用迭代器 next() 方法时,就会出现并发修改异常(ConcurrentModificationException)。下面的示例在执行时就会产生并发修改异常:

import java.util.*;

public class Demo {

    public static void main(String[] args) {
        List<String> list = new ArrayList<>();
        list.add("123");
        list.add("456");
        list.add("789");
        
        Iterator<String> iterator = list.iterator();
        while(iterator.hasNext()) {
            String value = iterator.next();
            if(value.equals("456")){
                list.add("999"); // 修改集合,添加新元素
            }
        }
    }
    
}

运行结果:

Exception in thread "main" java.util.ConcurrentModificationException
	at java.base/java.util.ArrayList$Itr.checkForComodification(ArrayList.java:1095)
	at java.base/java.util.ArrayList$Itr.next(ArrayList.java:1049)
	at Demo.main(Demo.java:13)

注意,抛出 ConcurrentModificationException 的原因是,如果在通过迭代器迭代时修改了集合,迭代器就会与集合不同步。

  

迭代期间移除元素

Iterator 接口有一个 remove() 方法,可让你从底层集合中删除 next() 刚刚返回的元素。调用 remove() 不会引发并发修改异常(ConcurrentModificationException)。

下面是一个在 Iterator 迭代期间从集合中移除元素的示例:

import java.util.*;

public class Demo {

    public static void main(String[] args) {
        List<String> list = new ArrayList<>();
        list.add("123");
        list.add("456");
        list.add("789");
        
        Iterator<String> iterator = list.iterator();
        while(iterator.hasNext()) {
            String value = iterator.next();
            if(value.equals("456")){
                iterator.remove(); // 移除元素
            }
        }

        System.out.println(Arrays.toString(list.toArray()));
        // 输出:[123, 789]
    }

}

  

forEachRemaining()

Iterator 的 forEachRemaining() 方法可在内部遍历 Iterator 中剩余的所有元素,并为每个元素调用作为 forEachRemaining() 参数的 Lambda 表达式。

下面是一个使用 Iterator 的 forEachRemaining() 方法的示例:

import java.util.*;

public class Demo {

    public static void main(String[] args) {
        List<String> list = new ArrayList<>();
        list.add("Jane");
        list.add("Heidi");
        list.add("Hannah");
        
        Iterator<String> iterator = list.iterator();
        // Lambda 表达式,迭代集合元素
        iterator.forEachRemaining((element) -> {
            System.out.println(element);
        });
    }
    
}

运行结果:

Jane
Heidi
Hannah

  

ListIterator

ListIterator 是 Java 集合框架中的一个接口,继承自 Iterator 接口,专门用于遍历 List 集合。它在 Iterator 的基础上增加了双向遍历、修改元素和获取索引位置等功能,更适合处理列表类型的集合。

ListIterator 接口的主要方法如下:

  • boolean hasNext():判断是否有下一个元素(正向遍历)

  • E next():返回下一个元素,并将迭代器指针后移

  • boolean hasPrevious():判断是否有前一个元素(反向遍历)

  • E previous():返回前一个元素,并将迭代器指针前移

  • int nextIndex():返回下一个元素的索引

  • int previousIndex():返回前一个元素的索引

  • void remove():删除 next() 或 previous() 方法最后返回的元素(继承自 Iterator,但实现更完善)

  • void set(E e):用指定元素替换 next() 或 previous() 方法最后返回的元素

  • void add(E e):在当前迭代位置插入指定元素

简单示例:

import java.util.ArrayList;
import java.util.List;
import java.util.ListIterator;

public class ListIteratorExample {
    public static void main(String[] args) {
        List<String> list = new ArrayList<>();
        list.add("A");
        list.add("B");
        list.add("C");
        
        ListIterator<String> iterator = list.listIterator();
        
        // 正向遍历
        System.out.println("正向遍历:");
        while (iterator.hasNext()) {
            System.out.println("索引 " + iterator.nextIndex() + ": " + iterator.next());
        }
        
        // 反向遍历
        System.out.println("\n反向遍历:");
        while (iterator.hasPrevious()) {
            System.out.println("索引 " + iterator.previousIndex() + ": " + iterator.previous());
        }
        
        // 添加元素
        iterator.add("D");
        System.out.println("\n添加元素后: " + list);
        
        // 修改元素
        iterator.next(); // 移动到元素"A"
        iterator.set("A+");
        System.out.println("修改元素后: " + list);
    }
}

运行结果:

正向遍历:
索引 0: A
索引 1: B
索引 2: C

反向遍历:
索引 2: C
索引 1: B
索引 0: A

添加元素后: [D, A, B, C]
修改元素后: [D, A+, B, C]

如你所见,这个示例首先通过所有元素正向遍历 ListIterator,然后再次反向遍历所有元素回到第一个元素。

  

自定义迭代器接口

如果你需要自定义迭代器,可以自己实现 Iterator 接口,创建一个可以遍历集合元素的迭代器。下面展示  Iterator 接口的一个简单的自定义实现,可让你了解自己实现 Iterator 接口的过程。

示例如下:

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

public class ListIteratorExample {

    public static void main(String[] args) {
        List<String> list = new ArrayList();
        list.add("one");
        list.add("two");
        list.add("three");

        ListIterator<String> iterator = new ListIterator<>(list);
        while(iterator.hasNext()) {
            System.out.println( iterator.next() );
        }
    }
    
}

/**
 * 自定义的迭代器类,实现了 Iterator 接口
 * 用于遍历 List 类型的集合
 * @param <T> 泛型参数,表示集合中元素的类型
 */
class ListIterator <T> implements Iterator<T> {
    // 存储要遍历的源集合
    private List<T> source = null;
    // 当前迭代的索引位置,初始值为0(指向第一个元素)
    private int index = 0;

    /**
     * 构造方法,初始化迭代器
     * @param source 要遍历的List集合
     */
    public ListIterator(List<T> source){
        this.source = source;
    }

    /**
     * 判断是否还有下一个元素
     * @return 如果存在下一个元素则返回true,否则返回false
     */
    @Override
    public boolean hasNext() {
        // 当当前索引小于集合大小,说明还有元素未遍历
        return this.index < this.source.size();
    }
    
    /**
     * 获取下一个元素,并将索引位置后移
     * @return 下一个元素
     */
    @Override
    public T next() {
        // 获取当前索引位置的元素,然后将索引加1
        return this.source.get(this.index++);
    }
}

运行结果:

one
two
three

  

  

说说我的看法
全部评论(
没有评论
关于
本网站专注于 Java、数据库(MySQL、Oracle)、Linux、软件架构及大数据等多领域技术知识分享。涵盖丰富的原创与精选技术文章,助力技术传播与交流。无论是技术新手渴望入门,还是资深开发者寻求进阶,这里都能为您提供深度见解与实用经验,让复杂编码变得轻松易懂,携手共赴技术提升新高度。如有侵权,请来信告知:hxstrive@outlook.com
其他应用
公众号