3077 字
约 10 分钟
10
第56章 Java Iterator迭代器
无标签

第56章 Java Iterator迭代器

面包屑导航 章节标题 学习目标

学习目标

  • 掌握Iterator接口的基本使用方法和核心概念
  • 学会使用Iterator进行安全的集合遍历和元素删除
  • 理解ListIterator的双向遍历和修改功能
  • 掌握增强for循环的使用和限制
  • 了解不同遍历方式的性能特点和适用场景
  • 学会选择最适合的集合遍历方法

Iterator概述

Iterator概述

Iterator(迭代器)是Java集合框架中用于遍历集合元素的标准接口。它提供了一种统一的方式来访问集合中的元素,而不需要了解集合的内部结构。Iterator模式是设计模式中的一种,它将遍历逻辑从集合类中分离出来,使得遍历操作更加灵活和安全。

Iterator的核心优势统一接口:为所有集合提供统一的遍历方式安全删除:支持在遍历过程中安全删除元素fail-fast机制:检测并发修改,抛出ConcurrentModificationException内存效率:不需要额外的索引变量,适合大型集合

Iterator类型

Iterator类型详解

Iterator接口

boolean hasNext()  // 检查是否有下一个元素
E next()          // 返回下一个元素
void remove()     // 删除当前元素(可选)
  • 单向遍历(只能向前)
  • 适用于所有Collection子类
  • 支持安全删除操作
  • fail-fast机制保证线程安全

ListIterator接口

boolean hasPrevious()  // 检查是否有前一个元素
E previous()           // 返回前一个元素
int nextIndex()        // 返回下一个元素索引
int previousIndex()    // 返回前一个元素索引
void set(E e)          // 修改当前元素
void add(E e)          // 在当前位置添加元素
  • 双向遍历(前进和后退)
  • 仅适用于List集合
  • 支持添加、修改、删除操作
  • 提供索引信息

增强for循环

for (ElementType element : collection) {
    // 处理元素
}
  • 基于Iterator实现的语法糖
  • 代码简洁易读
  • 适用于只读遍历
  • 编译时自动转换为Iterator

Iterator基础使用

Iterator基础使用

基本遍历示例

import java.util.*;

public class IteratorBasicExample {
    public static void main(String[] args) {
        // 创建ArrayList集合
        List<String> fruits = new ArrayList<>();
        fruits.add("苹果");
        fruits.add("香蕉");
        fruits.add("橙子");
        fruits.add("葡萄");
        
        System.out.println("原始集合: " + fruits);
        
        // 使用Iterator遍历集合
        System.out.println("\n使用Iterator遍历:");
        Iterator<String> iterator = fruits.iterator();
        while (iterator.hasNext()) {
            String fruit = iterator.next();
            System.out.println("- " + fruit);
        }
    }
}

安全删除操作

List<Integer> numbers = new ArrayList<>();
for (int i = 1; i <= 10; i++) {
    numbers.add(i);
}

System.out.println("删除前: " + numbers);

// 使用Iterator安全删除偶数
Iterator<Integer> iterator = numbers.iterator();
while (iterator.hasNext()) {
    Integer number = iterator.next();
    if (number % 2 == 0) {
        iterator.remove(); // 安全删除当前元素
        System.out.println("删除了: " + number);
    }
}

System.out.println("删除后: " + numbers);

避免ConcurrentModificationException在遍历集合时,如果直接使用集合的remove()方法删除元素,会抛出ConcurrentModificationException异常。正确的做法是使用Iterator的remove()方法。// ❌ 错误做法 - 会抛出异常
for (String item : list) {
if (condition) {
list.remove(item); // 抛出ConcurrentModificationException
}
}
// ✅ 正确做法 - 使用Iterator
Iterator iterator = list.iterator();
while (iterator.hasNext()) {
String item = iterator.next();
if (condition) {
iterator.remove(); // 安全删除
}
}

ListIterator双向遍历

ListIterator双向遍历

ListIterator是Iterator的子接口,专门用于List集合,提供了双向遍历的能力。它不仅可以向前遍历,还可以向后遍历,并且支持在遍历过程中添加、修改和删除元素。

import java.util.*;

public class ListIteratorExample {
    public static void main(String[] args) {
        List<String> cities = new ArrayList<>();
        cities.add("北京");
        cities.add("上海");
        cities.add("广州");
        cities.add("深圳");
        
        System.out.println("原始列表: " + cities);
        
        // 正向遍历
        System.out.println("\n正向遍历:");
        ListIterator<String> listIterator = cities.listIterator();
        while (listIterator.hasNext()) {
            int index = listIterator.nextIndex();
            String city = listIterator.next();
            System.out.println("索引 " + index + ": " + city);
        }
        
        // 反向遍历
        System.out.println("\n反向遍历:");
        while (listIterator.hasPrevious()) {
            int index = listIterator.previousIndex();
            String city = listIterator.previous();
            System.out.println("索引 " + index + ": " + city);
        }
    }
}

ListIterator修改操作

List<String> animals = new ArrayList<>();
animals.add("猫");
animals.add("狗");
animals.add("鸟");

System.out.println("初始列表: " + animals);

ListIterator<String> iterator = animals.listIterator();

// 在开头添加元素
iterator.add("鱼");
System.out.println("在开头添加'鱼': " + animals);

// 遍历并修改元素
while (iterator.hasNext()) {
    String animal = iterator.next();
    if (animal.equals("狗")) {
        iterator.set("小狗"); // 修改当前元素
        System.out.println("将'狗'修改为'小狗': " + animals);
    } else if (animal.equals("鸟")) {
        iterator.remove(); // 删除当前元素
        System.out.println("删除'鸟': " + animals);
        iterator.add("小鸟"); // 在当前位置添加新元素
        System.out.println("添加'小鸟': " + animals);
    }
}

System.out.println("最终列表: " + animals);

增强for循环

增强for循环详解

增强for循环(for-each循环)是Java 5引入的语法糖,它基于Iterator接口实现,提供了更简洁的集合遍历方式。编译器会自动将增强for循环转换为Iterator的使用。

// 遍历数组
int[] numbers = {1, 2, 3, 4, 5};
for (int number : numbers) {
    System.out.println("数字: " + number);
}

// 遍历List集合
List<String> fruits = Arrays.asList("苹果", "香蕉", "橙子");
for (String fruit : fruits) {
    System.out.println("水果: " + fruit);
}

// 遍历Set集合
Set<String> colors = new HashSet<>();
colors.add("红色");
colors.add("绿色");
colors.add("蓝色");

for (String color : colors) {
    System.out.println("颜色: " + color);
}

增强for循环的限制

使用限制无法获取索引:增强for循环中无法直接获取元素的索引位置无法修改集合结构:不能在遍历中添加或删除元素无法修改基本类型数组元素:对于基本类型数组,修改循环变量不会影响原数组只能单向遍历:无法实现双向遍历或跳跃式遍历

// 限制1:无法获取索引
List<String> items = Arrays.asList("A", "B", "C");
// 解决方案:使用传统for循环或手动计数
int index = 0;
for (String item : items) {
    System.out.println("索引 " + index + ": " + item);
    index++;
}

// 限制2:无法修改基本类型数组元素
int[] numbers = {1, 2, 3, 4, 5};
for (int number : numbers) {
    number = number * 2; // 只修改了局部变量,不影响原数组
}
System.out.println(Arrays.toString(numbers)); // 输出: [1, 2, 3, 4, 5]

// 正确的修改方式
for (int i = 0; i < numbers.length; i++) {
    numbers[i] = numbers[i] * 2;
}
System.out.println(Arrays.toString(numbers)); // 输出: [2, 4, 6, 8, 10]

性能比较

遍历方式性能比较

不同的遍历方式在不同类型的集合上有着不同的性能表现。了解这些性能特点有助于我们在实际开发中选择最适合的遍历方法。

遍历方式 适用集合 ArrayList性能 LinkedList性能 可读性 功能特点
传统for循环 List 优秀 (O(1)) 很差 (O(n²)) 中等 支持索引,可修改
Iterator 所有集合 良好 (O(n)) 良好 (O(n)) 良好 安全删除,统一接口
增强for循环 所有集合 良好 (O(n)) 良好 (O(n)) 最佳 只读遍历,代码简洁
Stream API 所有集合 中等 中等 良好 函数式编程,链式操作

性能要点说明ArrayList:支持随机访问,传统for循环性能最佳LinkedList:链表结构,索引访问需要遍历,Iterator性能最佳HashSet/TreeSet:不支持索引访问,只能使用Iterator或增强for循环大数据集:性能差异更加明显,选择合适的遍历方式很重要

最佳实践

遍历最佳实践

选择指南

推荐做法

// 1. 只读遍历使用增强for循环
for (String item : collection) {
    System.out.println(item);
}

// 2. 需要删除元素使用Iterator
Iterator<String> iterator = collection.iterator();
while (iterator.hasNext()) {
    if (shouldRemove(iterator.next())) {
        iterator.remove();
    }
}

// 3. ArrayList需要索引使用传统for循环
for (int i = 0; i < list.size(); i++) {
    System.out.println(i + ": " + list.get(i));
}

// 4. 使用removeIf方法(Java 8+)
list.removeIf(item -> shouldRemove(item));
  • 优先使用增强for循环进行只读遍历
  • 需要删除元素时使用Iterator
  • ArrayList需要索引时使用传统for循环
  • 利用Java 8的removeIf方法简化删除操作

避免的做法

// ❌ 在增强for循环中修改集合
for (String item : list) {
    if (condition) {
        list.remove(item); // 抛出异常
    }
}

// ❌ LinkedList使用索引访问
for (int i = 0; i < linkedList.size(); i++) {
    process(linkedList.get(i)); // O(n²)复杂度
}

// ❌ 重复获取集合大小
for (int i = 0; i < list.size(); i++) {
    // list.size()在每次循环中都被调用
}

// ❌ 不必要的类型转换
Iterator iterator = collection.iterator();
while (iterator.hasNext()) {
    String item = (String) iterator.next();
}
  • 避免在增强for循环中修改集合结构
  • 避免在LinkedList上使用索引访问
  • 避免在循环中重复计算集合大小
  • 避免不必要的类型转换,使用泛型

实际应用示例

实际应用示例

import java.util.*;

/**
 * Iterator实际应用示例
 * 演示在实际项目中如何正确使用Iterator
 */
public class IteratorPracticalExample {
    
    public static void main(String[] args) {
        // 创建任务列表
        List<String> tasks = new ArrayList<>();
        tasks.add("学习Java基础");
        tasks.add("完成作业");
        tasks.add("复习知识点");
        tasks.add("准备考试");
        
        System.out.println("任务列表: " + tasks);
        
        // 使用ListIterator在每个任务前添加序号
        addTaskNumbers(tasks);
        
        // 使用Iterator安全删除已完成的任务
        removeCompletedTasks(tasks, Arrays.asList("完成作业"));
        
        // 使用增强for循环显示最终任务列表
        displayTasks(tasks);
    }
    
    /**
     * 使用ListIterator为任务添加序号
     */
    private static void addTaskNumbers(List<String> tasks) {
        ListIterator<String> iterator = tasks.listIterator();
        int taskNumber = 1;
        
        while (iterator.hasNext()) {
            String task = iterator.next();
            iterator.set(taskNumber + ". " + task);
            taskNumber++;
        }
        
        System.out.println("\n添加序号后: " + tasks);
    }
    
    /**
     * 使用Iterator安全删除已完成的任务
     */
    private static void removeCompletedTasks(List<String> tasks, 
                                           List<String> completedTasks) {
        Iterator<String> iterator = tasks.iterator();
        
        while (iterator.hasNext()) {
            String task = iterator.next();
            // 检查任务是否已完成(忽略序号)
            for (String completed : completedTasks) {
                if (task.contains(completed)) {
                    iterator.remove();
                    System.out.println("删除已完成任务: " + task);
                    break;
                }
            }
        }
    }
    
    /**
     * 使用增强for循环显示任务列表
     */
    private static void displayTasks(List<String> tasks) {
        System.out.println("\n最终任务列表:");
        for (String task : tasks) {
            System.out.println(task);
        }
    }
}

💻 查看完整代码 - 在线IDE体验 常见问题

常见问题解答

Q: 什么时候使用Iterator而不是增强for循环?A: 当需要在遍历过程中删除元素时,或者需要更精细的遍历控制时,应该使用Iterator。增强for循环适合只读遍历。

Q: ListIterator和Iterator有什么区别?A: ListIterator支持双向遍历,可以向前和向后移动,还支持添加和修改元素操作,但仅适用于List集合。Iterator只支持单向遍历,适用于所有Collection。

Q: 为什么LinkedList不应该使用索引访问?A: LinkedList是链表结构,索引访问需要从头开始遍历到指定位置,时间复杂度为O(n)。在循环中使用索引访问会导致O(n²)的时间复杂度,性能很差。

Q: 增强for循环的内部实现是什么?A: 增强for循环在编译时会被转换为Iterator的使用。这就是为什么它适用于所有实现Iterable接口的集合,也是为什么在增强for循环中不能修改集合结构的原因。

本章小结

本章小结

  • Iterator是Java集合框架中用于遍历集合元素的标准接口,提供了统一的遍历方式
  • Iterator支持安全删除操作,避免了ConcurrentModificationException异常
  • ListIterator是Iterator的子接口,支持双向遍历和更多的修改操作,仅适用于List集合
  • 增强for循环是基于Iterator实现的语法糖,提供了简洁的只读遍历方式
  • 不同遍历方式在不同集合类型上有不同的性能表现,需要根据场景选择
  • ArrayList适合使用传统for循环进行索引访问,LinkedList适合使用Iterator遍历
  • 在需要删除元素时应使用Iterator.remove()或removeIf()方法,避免直接修改集合
  • 理解各种遍历方式的优缺点和适用场景,有助于编写高效的Java代码

导航链接 上一章:Queue接口 章节测试 下一章:Map接口 JavaScript

第56章 Java Iterator迭代器
https://clxhxhhr.top/posts/3001/
作者
clxstart
发布于
2026-09-24
许可协议
CC BY-NC-SA 4.0
评论
0 条
还没有评论,先写一条吧。