Iterator 接口位于 java.util 包中,表示一个能够在 Java 对象集合中一次遍历一个对象的对象,还是 Java 中最古老的对象集合迭代机制之一(Enumerator 比 Iterator 还要古老)。
Iterator 接口提供了一种标准的方法来遍历集合中的元素,而无需关心集合的具体实现方式。使用它可以在不暴露集合内部结构的情况下,对集合中的元素进行访问和操作。
注意,要使用 Iterator,必须从要遍历的集合对象中获取一个 Iterator 实例。获取的 Iterator 会跟踪底层集合中的元素,以确保遍历所有元素。如果在遍历指向的底层集合时修改了该集合(如删除了元素),迭代器通常会检测到,并在下次尝试从迭代器中获取下一个元素时抛出异常。
Iterator 接口相当简单,核心方法如下:
hasNext():检查集合中是否还有下一个元素。如果有,返回 true;否则返回 false。
next():返回集合中的下一个元素,并将迭代器的位置向后移动一位。如果没有下一个元素,会抛出 NoSuchElementException 异常。
remove():移除迭代器最后返回的元素。该方法只能在每次调用 next() 方法之后调用一次,如果违反此规则,会抛出 IllegalStateException 异常。
forEachRemaining():对迭代器中的所有剩余元素进行迭代,并调用 Lambda 表达式,将每个剩余元素作为参数传递给该 Lambda 表达式。
这些方法中的每一个都将在以下部分中详细介绍。
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
你可以使用 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]
}
}
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 是 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
更多内容参考https://docs.oracle.com/javase/8/docs/api/java/util/Iterator.html API 文档。