0Pricing
Java Academy · 课时

Iterable 与 Iterator 契约

理解 Iterable 和 Iterator 接口,以及 for-each 循环在内部的工作方式

Iterable 与 Iterator 契约 是 CoddyKit 上的免费 Java Academy 课时。 这是第 1 节课,共 4 节。 你可以在下方免费阅读本课时的完整内容 — 然后在浏览器中使用内置代码编辑器和全天候 AI 导师进行实践。 这是 Java Academy 学习路径的一部分,你的进度在网页和 CoddyKit 应用中同步。 Java Academy 课程共包含 4 节课。

Iterable 与 Iterator

Iterable<T> 和 Iterator<T> 是支持 Java 增强 for 循环的接口。理解它们后,您就可以让自己的数据结构支持循环遍历。

Iterable 接口

Iterable<T> 有一个方法:iterator(),它返回一个 Iterator<T>。实现 Iterable 的任何类都可以用于增强 for 循环。

// java.lang.Iterable<T>
interface Iterable<T> {
    Iterator<T> iterator();
    // default: forEach, spliterator (Java 8+)
}

// Any class implementing Iterable<T> works in for-each:
class Range implements Iterable<Integer> {
    private final int start, end;
    Range(int start, int end) { this.start = start; this.end = end; }

    public Iterator<Integer> iterator() {
        return new RangeIterator(); // defined separately
    }
}

Iterator 接口

Iterator<T> 有三个方法:hasNext()、next() 和可选的 remove()。

// java.util.Iterator<T>
interface Iterator<T> {
    boolean hasNext(); // true if more elements
    T next();          // returns next element, advances cursor
    default void remove() { throw new UnsupportedOperationException(); }
}

// How for-each desugars internally:
// for (T item : iterable) { use(item); }
// becomes:
Iterator<T> it = iterable.iterator();
while (it.hasNext()) {
    T item = it.next();
    // use(item)
}

增强 For 循环的展开

增强 for 循环是 Iterable/Iterator 模式的语法糖。理解这一点有助于您正确编写自定义 Iterable。

List<String> names = List.of("Alice", "Bob", "Charlie");

// For-each (readable way)
for (String name : names) {
    System.out.println(name);
}

// Equivalent explicit form
Iterator<String> it = names.iterator();
while (it.hasNext()) {
    String name = it.next();
    System.out.println(name);
}

Iterator 游标状态

Iterator 会维护一个游标——也就是序列中的一个位置。调用 next() 会使游标向前移动。遍历完成后,Iterator 无法重置。

List<Integer> nums = List.of(1, 2, 3);
Iterator<Integer> it = nums.iterator();

System.out.println(it.hasNext()); // true
System.out.println(it.next());    // 1
System.out.println(it.next());    // 2
System.out.println(it.next());    // 3
System.out.println(it.hasNext()); // false

try {
    it.next(); // NoSuchElementException
} catch (java.util.NoSuchElementException e) {
    System.out.println("No more elements!");
}

ConcurrentModificationException

使用显式 Iterator 进行遍历时,如果在遍历过程中修改集合(Iterator.remove() 除外),就会抛出 ConcurrentModificationException。

List<String> list = new ArrayList<>(List.of("a", "b", "c", "d"));

// BAD: modifying collection during for-each
try {
    for (String s : list) {
        if ("b".equals(s)) list.remove(s); // ConcurrentModificationException!
    }
} catch (java.util.ConcurrentModificationException e) {
    System.out.println("Cannot modify during iteration!");
}

// GOOD: use Iterator.remove()
Iterator<String> it = list.iterator();
while (it.hasNext()) {
    if ("b".equals(it.next())) it.remove(); // safe
}
System.out.println(list); // [a, c, d]

多个 Iterator

每次调用 iterator() 都会返回一个全新且独立的 Iterator。同一个集合上可以同时运行多个 Iterator。

List<Integer> nums = List.of(1, 2, 3);

Iterator<Integer> a = nums.iterator();
Iterator<Integer> b = nums.iterator();

System.out.println(a.next()); // 1
System.out.println(b.next()); // 1 (independent cursor)
System.out.println(a.next()); // 2
System.out.println(b.next()); // 2

Iterable 与 Iterator

关键区别:

  • Iterable:能够生成 Iterator 的数据源,可以遍历多次
  • Iterator:指向序列的游标,只能使用一次,并且具有状态
// Iterable: reusable
List<String> list = List.of("x", "y");
for (String s : list) {} // OK
for (String s : list) {} // OK again — new iterator each time

// Iterator: single-use
Iterator<String> it = list.iterator();
while (it.hasNext()) it.next();
// for (String s : it) {} // compile error — Iterator is not Iterable!

实践:自定义文件行 Iterable

一个实现 Iterable 的文件读取器,使您可以使用增强 for 循环遍历文件中的各行。

import java.io.*;
import java.util.*;

class FileLines implements Iterable<String>, Closeable {
    private final BufferedReader reader;

    FileLines(String path) throws IOException {
        this.reader = new BufferedReader(new FileReader(path));
    }

    public Iterator<String> iterator() {
        return new Iterator<>() {
            private String nextLine = readNext();

            private String readNext() {
                try { return reader.readLine(); }
                catch (IOException e) { return null; }
            }

            public boolean hasNext() { return nextLine != null; }
            public String next() {
                String curr = nextLine;
                nextLine = readNext();
                return curr;
            }
        };
    }

    public void close() throws IOException { reader.close(); }
}

forEach 默认方法

Java 8 为 Iterable 添加了默认的 forEach(Consumer) 方法。这是显式编写循环的一种便捷替代方式。

List<String> cities = List.of("New York", "London", "Tokyo");

// for-each loop
for (String city : cities) System.out.println(city);

// forEach with lambda
cities.forEach(city -> System.out.println(city));

// forEach with method reference (most concise)
cities.forEach(System.out::println);

// For transforming: use stream
cities.stream()
    .map(String::toUpperCase)
    .forEach(System.out::println);

Iterator 模式的实际应用

以下是适合实现 Iterable/Iterator 的场景:

  • 自定义数据结构(树、图、链表)
  • 按需生成元素的惰性序列
  • 基于资源的序列(文件行、数据库游标、消息队列)

快速检查

使用增强 for 循环遍历集合时修改集合,会抛出什么异常?

回顾:Iterable 与 Iterator 契约

要点:

  • Iterable<T> 有一个方法:iterator()——支持增强 for 循环
  • Iterator<T> 有 hasNext()、next() 和可选的 remove()
  • 增强 for 循环是 Iterable/Iterator 模式的语法糖
  • 多次调用 iterator() 可获得彼此独立的全新游标
  • 切勿在增强 for 循环期间修改集合——请改用 Iterator.remove()
  • 为自定义数据结构实现 Iterable,以支持增强 for 循环

常见问题解答

「Iterable 与 Iterator 契约」课时是免费的吗?

是的 — 「Iterable 与 Iterator 契约」的完整文本可在网页上免费阅读。要进行交互式练习(内置代码编辑器和全天候 AI 导师)并解锁 Java Academy 课程的其余内容,请升级到 CoddyKit PRO。 Java Academy 课程共包含 4 节课。

「Iterable 与 Iterator 契约」这节课中我会学到什么?

理解 Iterable 和 Iterator 接口,以及 for-each 循环在内部的工作方式 你通过在浏览器中直接运行的动手代码来练习 Java Academy,全天候 AI 导师会在你学习这节课的过程中回答你的问题。

学习 Java Academy 需要有经验吗?

无需任何先前经验。CoddyKit 上的 Java Academy 课程适合初学者到高级学习者,你可以从这里开始或从头开始,按照自己的节奏学习。 这是第 1 节课,共 4 节。

「Iterable 与 Iterator 契约」课时需要多长时间?

大多数 CoddyKit 课程大约需要 5–10 分钟。每节课都很精短且互动,所以你能稳步进步,并在网页和应用中从离开的地方继续。

我能在这节 Java Academy 课中编写并运行代码吗?

能。每节 Java Academy 课都包含内置代码编辑器,你可以在浏览器中直接编写并运行真实代码,并获得即时 AI 反馈 — 无需本地设置。

此课程中的所有课时

  1. Iterable 与 Iterator 契约
  2. 实现自定义迭代器
  3. ListIterator 与双向遍历
  4. 快速失败与安全失败迭代器
← 返回 Java Academy