Java 迭代器模式从入门到实战(后端必看,附案例+面试考点)
前言:迭代器模式(Iterator Pattern)是Java设计模式中最常用的"行为型模式"之一,核心是"分离集合的遍历与存储"------提供一种统一的方式遍历不同结构的集合(如List、Set、Map),无需暴露集合的内部实现细节,让遍历逻辑与集合本身解耦。
很多Java后端开发者在开发中会遇到这样的问题:面对不同类型的集合(如ArrayList、HashSet、自定义集合),需要写不同的遍历逻辑,代码冗余且耦合度高;面试时被问到"Java中的Iterator接口原理是什么""迭代器模式的核心优势""快速失败和安全失败的区别",常常答不全面。
本文从入门到实战,用极简语言拆解迭代器模式核心,结合可直接复制运行的入门案例、真实业务实战(Spring Boot环境),以及高频面试考点,带你吃透迭代器模式------新手能快速上手,中级开发者能落地项目,面试时能轻松应对追问,看完就能用在实际开发中。
一、为什么Java后端必须掌握迭代器模式?(痛点直击)
先看3个Java后端开发中最常见的场景,你一定遇到过,这也是迭代器模式的核心应用场景,更是面试中高频提及的"解耦"典型场景:
-
场景1:开发电商购物车功能,购物车底层可能用ArrayList存储商品(有序),也可能用HashSet存储(去重),若为每种集合单独写遍历逻辑,代码冗余,后续切换集合类型需修改大量遍历代码;
-
场景2:自定义集合(如树形结构集合、链表集合),需要提供遍历功能,若将遍历逻辑写在集合内部,会导致集合职责过重(既负责存储,又负责遍历),违背单一职责原则;
-
场景3:团队协作开发中,多个开发者需要遍历同一个集合,若每个人都写自己的遍历逻辑,易出现bug(如并发遍历异常),且代码难以维护、统一修改成本高。
这些场景的共性问题:集合的遍历逻辑与存储逻辑耦合,不同集合的遍历方式不统一,集合内部实现暴露,代码冗余、可维护性差,违背单一职责原则。
而迭代器模式的核心价值,就是"解耦+统一"------将遍历逻辑从集合中分离出来,封装成独立的迭代器对象,提供统一的遍历接口(hasNext()、next()),无论集合的底层结构如何变化,遍历方式保持一致,且无需暴露集合的内部实现。
简单说,迭代器模式就是"集合的专属遍历工具":集合只负责存储数据,迭代器只负责遍历数据,两者各司其职、互不干扰。比如ArrayList和HashSet,底层实现完全不同,但都可以通过Iterator迭代器统一遍历,开发者无需关心集合内部是数组还是哈希表,只需调用迭代器的方法即可。
核心结论:迭代器模式不是"花里胡哨"的设计,而是后端开发的"遍历神器"------初级开发者用它简化遍历逻辑、减少代码冗余,中级开发者用它设计可扩展的自定义集合,高级开发者用它理解JDK源码(如Iterator、ListIterator),面试时更是高频考点(中高级岗位必问)。
二、迭代器模式核心概念(极简入门,无需死记硬背)
迭代器模式的本质很简单:定义迭代器接口,封装遍历逻辑,集合类提供获取迭代器的方法,通过迭代器对象遍历集合,实现"遍历与存储"的分离。
就像图书馆的书架:书架(集合)负责存储书籍(数据),图书管理员(迭代器)负责帮你遍历书架上的书籍;你无需知道书架是分层还是分类摆放(内部实现),只需告诉管理员"下一本",管理员就会帮你找到,两者互不干扰。
2.1 核心角色(4个核心,必记,区分角色是掌握迭代器模式的关键)
-
迭代器接口(Iterator):定义统一的遍历方法,核心是两个方法------hasNext()(判断是否还有下一个元素)、next()(获取下一个元素),可选提供remove()(删除当前元素);
-
具体迭代器(ConcreteIterator):实现迭代器接口,封装具体集合的遍历逻辑,持有集合的引用,记录当前遍历位置;
-
聚合接口(Aggregate):定义集合的核心方法,重点是提供一个获取迭代器的方法(如iterator()),规范所有集合必须提供迭代器;
-
具体聚合(ConcreteAggregate):实现聚合接口,是具体的集合类(如自定义链表、自定义数组),负责创建对应的具体迭代器,存储数据。
核心原则:聚合管存储,迭代器管遍历;两者解耦,迭代器依赖聚合,聚合不依赖迭代器,新增集合类型只需新增对应的迭代器,无需修改原有代码。这是迭代器模式的灵魂,也是它与直接遍历集合的核心区别。
核心注意点:迭代器模式解决的是"不同集合统一遍历、遍历与存储解耦"的问题,与工厂模式的"对象创建"、策略模式的"算法切换"有本质区别。
2.2 迭代器模式的核心流程(一句话看懂)
具体聚合(集合)初始化,存储数据 → 客户端调用集合的iterator()方法,获取具体迭代器 → 客户端通过迭代器的hasNext()判断是否有下一个元素 → 调用next()获取元素,完成遍历 → 可选调用remove()删除当前元素。
三、迭代器模式入门实现(附可复制代码,新手必练)
以"自定义书架集合"为入门案例,模拟一个存储书籍的书架(底层用数组实现),用迭代器模式实现遍历,对比"直接遍历集合"和"迭代器模式遍历"的差异,一看就懂、一练就会。
3.1 普通实现:直接遍历的反例(痛点凸显)
若不使用迭代器模式,直接在集合内部写遍历逻辑,或客户端直接操作集合的底层存储,会导致集合职责过重、内部实现暴露,后续修改集合底层结构(如数组改为链表),需修改所有遍历代码。
java
// 自定义书架集合(底层用数组实现)
public class BookShelf {
private Book[] books; // 底层存储:数组
private int size; // 书籍数量
public BookShelf(int capacity) {
this.books = new Book[capacity];
this.size = 0;
}
// 添加书籍
public void addBook(Book book) {
if (size < books.length) {
books[size++] = book;
}
}
// 获取底层数组(暴露内部实现,风险高)
public Book[] getBooks() {
return books;
}
// 获取书籍数量
public int getSize() {
return size;
}
// 内部遍历逻辑(集合职责过重,违背单一职责)
public void traverse() {
for (int i = 0; i < size; i++) {
System.out.println(books[i].getName());
}
}
}
// 书籍实体类
class Book {
private String name;
public Book(String name) {
this.name = name;
}
public String getName() {
return name;
}
}
// 客户端调用(直接操作集合底层,耦合度高)
public class Client {
public static void main(String[] args) {
BookShelf bookShelf = new BookShelf(5);
bookShelf.addBook(new Book(《Java设计模式入门》));
bookShelf.addBook(new Book(《Spring Boot实战》));
bookShelf.addBook(new Book(《MySQL进阶》));
// 方式1:调用集合内部的遍历方法(集合职责过重)
bookShelf.traverse();
// 方式2:客户端直接操作底层数组(暴露内部实现,耦合度高)
Book[] books = bookShelf.getBooks();
for (int i = 0; i < bookShelf.getSize(); i++) {
System.out.println(books[i].getName());
}
// 痛点:若BookShelf底层改为链表,getBooks()方法失效,客户端遍历代码需全部修改
// 集合既负责存储,又负责遍历,职责混乱
}
}
【运行结果】:
text
Java设计模式入门
Spring Boot实战
MySQL进阶
Java设计模式入门
Spring Boot实战
MySQL进阶
【缺点极其明显】:
-
耦合度极高:客户端直接依赖集合的底层实现(数组),若集合底层修改(如改为链表),客户端遍历代码需全部修改;
-
职责混乱:集合既负责存储数据,又负责遍历数据,违背单一职责原则,后续维护难度大;
-
内部实现暴露:getBooks()方法直接返回底层数组,客户端可随意修改数组内容,存在安全风险;
-
扩展性差:新增集合类型(如树形书架),需重新写遍历逻辑,无法统一遍历方式。
3.2 迭代器模式实现:解耦的优雅代码(正例)
用迭代器模式重构书架案例,定义迭代器接口和聚合接口,将遍历逻辑封装到迭代器中,集合只负责存储数据,提供获取迭代器的方法,客户端通过迭代器遍历集合,无需关心集合底层实现。
java
// 1. 迭代器接口(定义统一遍历方法)
public interface Iterator {
// 判断是否还有下一个元素
boolean hasNext();
// 获取下一个元素
Object next();
// 可选:删除当前元素(默认空实现,避免子类强制实现)
default void remove() {
throw new UnsupportedOperationException("不支持删除操作");
}
}
// 2. 聚合接口(定义获取迭代器的方法)
public interface Aggregate {
// 获取迭代器
Iterator iterator();
}
// 3. 书籍实体类(不变)
class Book {
private String name;
public Book(String name) {
this.name = name;
}
public String getName() {
return name;
}
}
// 4. 具体聚合:自定义书架集合(实现Aggregate接口)
public class BookShelf implements Aggregate {
private Book[] books; // 底层存储:数组
private int size; // 书籍数量
public BookShelf(int capacity) {
this.books = new Book[capacity];
this.size = 0;
}
// 添加书籍
public void addBook(Book book) {
if (size < books.length) {
books[size++] = book;
}
}
// 提供获取指定位置书籍的方法(供迭代器使用,不暴露底层数组)
public Book getBookAt(int index) {
if (index < size) {
return books[index];
}
return null;
}
// 获取书籍数量(供迭代器使用)
public int getSize() {
return size;
}
// 核心:返回具体迭代器
@Override
public Iterator iterator() {
return new BookShelfIterator(this);
}
}
// 5. 具体迭代器:书架迭代器(实现Iterator接口)
public class BookShelfIterator implements Iterator {
private BookShelf bookShelf; // 持有聚合(书架)的引用
private int index; // 记录当前遍历位置
// 构造方法:注入书架,初始化遍历位置为0
public BookShelfIterator(BookShelf bookShelf) {
this.bookShelf = bookShelf;
this.index = 0;
}
// 判断是否还有下一本书
@Override
public boolean hasNext() {
// 遍历位置小于书籍数量,说明还有下一本
return index < bookShelf.getSize();
}
// 获取下一本书
@Override
public Object next() {
if (!hasNext()) {
throw new NoSuchElementException("没有更多元素");
}
// 获取当前位置的书籍,然后遍历位置+1
Book book = bookShelf.getBookAt(index);
index++;
return book;
}
// 可选:重写remove方法,实现删除当前元素
@Override
public void remove() {
// 若删除当前元素,后续元素需前移,简化实现
if (index <= 0) {
throw new IllegalStateException("next()方法未被调用,无法删除");
}
// 这里简化实现,实际开发中需处理数组前移逻辑
System.out.println("删除书籍:" + bookShelf.getBookAt(index-1).getName());
bookShelf.getBookAt(index-1) = null;
index--;
bookShelf.size--;
}
}
// 6. 客户端调用(通过迭代器遍历,与集合底层解耦)
public class Client {
public static void main(String[] args) {
// 1. 创建具体聚合(书架),添加书籍
BookShelf bookShelf = new BookShelf(5);
bookShelf.addBook(new Book(《Java设计模式入门》));
bookShelf.addBook(new Book(《Spring Boot实战》));
bookShelf.addBook(new Book(《MySQL进阶》));
// 2. 获取迭代器
Iterator iterator = bookShelf.iterator();
// 3. 通过迭代器遍历集合(统一遍历方式,与底层无关)
System.out.println("书架书籍遍历:");
while (iterator.hasNext()) {
Book book = (Book) iterator.next();
System.out.println(book.getName());
}
// 4. 可选:删除元素
iterator = bookShelf.iterator(); // 重置迭代器
if (iterator.hasNext()) {
iterator.next(); // 指向第一本书
iterator.remove(); // 删除第一本书
}
// 5. 再次遍历,查看删除效果
System.out.println("删除后遍历:");
iterator = bookShelf.iterator();
while (iterator.hasNext()) {
Book book = (Book) iterator.next();
System.out.println(book.getName());
}
// 亮点:若BookShelf底层改为链表,只需新增BookShelfIterator的链表实现
// 客户端遍历代码无需修改,完全解耦
}
}
【运行结果】:
text
书架书籍遍历:
Java设计模式入门
Spring Boot实战
MySQL进阶
删除书籍:Java设计模式入门
删除后遍历:
Spring Boot实战
MySQL进阶
【代码优势极其明显】:
-
解耦彻底:客户端只依赖迭代器接口,不依赖集合的底层实现,集合底层修改(数组→链表),客户端代码无需修改;
-
职责清晰:集合只负责存储数据,迭代器只负责遍历数据,符合单一职责原则,后续维护更便捷;
-
内部实现隐藏:客户端无法直接操作集合底层存储,只能通过迭代器访问,提升代码安全性;
-
扩展性极强:新增集合类型(如树形书架),只需新增对应的聚合类和迭代器类,无需修改原有代码,符合"开闭原则";
-
遍历统一:无论集合底层结构如何,客户端都通过hasNext()、next()方法遍历,代码更简洁、统一。
【核心总结】:迭代器模式的核心不是"实现遍历",而是"解耦遍历与存储"------通过接口抽象,将遍历逻辑封装成独立的迭代器,让集合和迭代器各司其职,既保证了遍历的统一性,又提升了代码的可扩展性和安全性,解决了直接遍历的耦合痛点。
四、迭代器模式实战(真实业务场景,可直接复用)
结合Java后端最常见的"商品集合遍历"场景,用迭代器模式实现"电商系统中,统一遍历不同类型的商品集合(热销商品、新品商品、折扣商品)",贴合真实项目开发(Spring Boot环境),代码可直接复制到项目中使用,解决实际开发中的遍历解耦痛点。
4.1 实战场景说明
场景:电商系统中,商品列表有3种类型,底层存储结构不同,需要提供统一的遍历方式,后续可能新增更多商品类型:
-
热销商品集合:底层用ArrayList实现(有序,可重复);
-
新品商品集合:底层用HashSet实现(无序,去重);
-
折扣商品集合:底层用LinkedList实现(有序,插入删除高效);
-
核心需求:统一遍历这3种商品集合,无需关心底层存储结构,支持新增商品集合类型时,不修改原有遍历代码,贴合Spring Boot实战规范,支持依赖注入、统一异常处理。
-
迭代器接口:定义统一的商品遍历方法,支持泛型(避免强制转换);
-
聚合接口:定义商品集合的核心方法,提供获取迭代器的方法;
-
具体聚合:3种商品集合,实现聚合接口,创建对应迭代器;
-
实战亮点:结合Spring依赖注入、泛型、统一异常处理,实现迭代器的自动注入,贴合真实项目开发规范,可直接复用。
4.2 实战代码实现(Spring Boot环境,可直接复用)
java
// 1. 公共实体:商品实体类
@Data
public class Product {
private Long productId;
private String productName;
private Double price;
private String type; // 商品类型:HOT(热销)、NEW(新品)、DISCOUNT(折扣)
}
// 2. 公共实体:响应结果封装
@Data
public class Result {
private Integer code; // 200成功,500失败
private String message;
private Object data;
public static Result success(String message, Object data) {
Result result = new Result();
result.setCode(200);
result.setMessage(message);
result.setData(data);
return result;
}
public static Result fail(String message) {
Result result = new Result();
result.setCode(500);
result.setMessage(message);
return result;
}
}
// 3. 迭代器接口(泛型,支持商品类型,避免强制转换)
public interface ProductIterator {
// 判断是否还有下一个商品
boolean hasNext();
// 获取下一个商品
Product next();
// 删除当前商品
default void remove() {
throw new UnsupportedOperationException("不支持删除商品操作");
}
}
// 4. 聚合接口(商品集合接口)
public interface ProductAggregate {
// 添加商品
void addProduct(Product product);
// 获取迭代器
ProductIterator iterator();
// 获取商品数量
int getSize();
}
// 5. 具体聚合1:热销商品集合(底层ArrayList)
@Component
public class HotProductAggregate implements ProductAggregate {
private final List<Product> productList = new ArrayList<>();
@Override
public void addProduct(Product product) {
product.setType("HOT");
productList.add(product);
}
@Override
public ProductIterator iterator() {
// 返回热销商品迭代器
return new HotProductIterator(productList);
}
@Override
public int getSize() {
return productList.size();
}
// 具体迭代器:热销商品迭代器(内部类,与集合绑定)
static class HotProductIterator implements ProductIterator {
private final List<Product> productList;
private int index;
public HotProductIterator(List<Product> productList) {
this.productList = productList;
this.index = 0;
}
@Override
public boolean hasNext() {
return index < productList.size();
}
@Override
public Product next() {
if (!hasNext()) {
throw new NoSuchElementException("没有更多热销商品");
}
return productList.get(index++);
}
}
}
// 5. 具体聚合2:新品商品集合(底层HashSet)
@Component
public class NewProductAggregate implements ProductAggregate {
private final Set<Product> productSet = new HashSet<>();
@Override
public void addProduct(Product product) {
product.setType("NEW");
productSet.add(product);
}
@Override
public ProductIterator iterator() {
// 返回新品商品迭代器(将Set转为List遍历,简化实现)
return new NewProductIterator(new ArrayList<>(productSet));
}
@Override
public int getSize() {
return productSet.size();
}
// 具体迭代器:新品商品迭代器
static class NewProductIterator implements ProductIterator {
private final List<Product> productList;
private int index;
public NewProductIterator(List<Product> productList) {
this.productList = productList;
this.index = 0;
}
@Override
public boolean hasNext() {
return index < productList.size();
}
@Override
public Product next() {
if (!hasNext()) {
throw new NoSuchElementException("没有更多新品商品");
}
return productList.get(index++);
}
}
}
// 5. 具体聚合3:折扣商品集合(底层LinkedList)
@Component
public class DiscountProductAggregate implements ProductAggregate {
private final LinkedList<Product> productList = new LinkedList<>();
@Override
public void addProduct(Product product) {
product.setType("DISCOUNT");
productList.add(product);
}
@Override
public ProductIterator iterator() {
// 返回折扣商品迭代器
return new DiscountProductIterator(productList);
}
@Override
public int getSize() {
return productList.size();
}
// 具体迭代器:折扣商品迭代器
static class DiscountProductIterator implements ProductIterator {
private final LinkedList<Product> productList;
private int index;
public DiscountProductIterator(LinkedList<Product> productList) {
this.productList = productList;
this.index = 0;
}
@Override
public boolean hasNext() {
return index < productList.size();
}
@Override
public Product next() {
if (!hasNext()) {
throw new NoSuchElementException("没有更多折扣商品");
}
return productList.get(index++);
}
}
}
// 6. 服务层:商品服务(统一管理所有商品集合,提供遍历接口)
@Service
public class ProductService {
// 注入所有商品集合(Spring自动将ProductAggregate实现类注入到List中)
private final List<ProductAggregate> productAggregates;
// 构造方法注入
public ProductService(List<ProductAggregate> productAggregates) {
this.productAggregates = productAggregates;
}
// 统一遍历所有类型的商品集合
public Result traverseAllProducts() {
try {
Map<String, List<Product>> allProducts = new HashMap<>();
for (ProductAggregate aggregate : productAggregates) {
ProductIterator iterator = aggregate.iterator();
List<Product> productList = new ArrayList<>();
while (iterator.hasNext()) {
productList.add(iterator.next());
}
// 根据商品类型分类存储
if (!productList.isEmpty()) {
String type = productList.get(0).getType();
allProducts.put(type, productList);
}
}
return Result.success("商品遍历成功", allProducts);
} catch (Exception e) {
return Result.fail("商品遍历失败:" + e.getMessage());
}
}
// 新增商品(根据类型添加到对应集合)
public Result addProduct(Product product, String type) {
try {
for (ProductAggregate aggregate : productAggregates) {
// 简化判断:根据集合实例判断类型(真实项目可用策略模式优化)
if (aggregate instanceof HotProductAggregate && "HOT".equals(type)) {
aggregate.addProduct(product);
return Result.success("热销商品添加成功", null);
} else if (aggregate instanceof NewProductAggregate && "NEW".equals(type)) {
aggregate.addProduct(product);
return Result.success("新品商品添加成功", null);
} else if (aggregate instanceof DiscountProductAggregate && "DISCOUNT".equals(type)) {
aggregate.addProduct(product);
return Result.success("折扣商品添加成功", null);
}
}
return Result.fail("商品类型不存在");
} catch (Exception e) {
return Result.fail("商品添加失败:" + e.getMessage());
}
}
}
// 7. 控制层:接口对外提供访问(Spring Boot Controller)
@RestController
@RequestMapping("/product")
public class ProductController {
private final ProductService productService;
public ProductController(ProductService productService) {
this.productService = productService;
}
// 新增商品
@PostMapping("/add")
public Result addProduct(@RequestBody Product product, @RequestParam String type) {
return productService.addProduct(product, type);
}
// 统一遍历所有商品
@GetMapping("/traverse")
public Result traverseAllProducts() {
return productService.traverseAllProducts();
}
}
// 8. 测试类(模拟接口调用,Spring Boot环境可直接注入测试)
public class ProductIteratorTest {
public static void main(String[] args) {
// 模拟Spring容器注入所有商品集合
List<ProductAggregate> aggregates = new ArrayList<>();
HotProductAggregate hotAggregate = new HotProductAggregate();
NewProductAggregate newAggregate = new NewProductAggregate();
DiscountProductAggregate discountAggregate = new DiscountProductAggregate();
// 新增商品
Product p1 = new Product();
p1.setProductId(1L);
p1.setProductName("手机");
p1.setPrice(3999.0);
hotAggregate.addProduct(p1);
Product p2 = new Product();
p2.setProductId(2L);
p2.setProductName("平板");
p2.setPrice(2999.0);
newAggregate.addProduct(p2);
Product p3 = new Product();
p3.setProductId(3L);
p3.setProductName("耳机");
p3.setPrice(499.0);
discountAggregate.addProduct(p3);
aggregates.add(hotAggregate);
aggregates.add(newAggregate);
aggregates.add(discountAggregate);
// 初始化商品服务
ProductService productService = new ProductService(aggregates);
// 测试统一遍历
System.out.println(productService.traverseAllProducts());
// 测试新增商品
Product p4 = new Product();
p4.setProductId(4L);
p4.setProductName("电脑");
p4.setPrice(5999.0);
System.out.println(productService.addProduct(p4, "HOT"));
// 再次遍历,查看新增效果
System.out.println(productService.traverseAllProducts());
}
}
【运行结果】:
text
Result(code=200, message=商品遍历成功, data={HOT=[Product(productId=1, productName=手机, price=3999.0, type=HOT)], NEW=[Product(productId=2, productName=平板, price=2999.0, type=NEW)], DISCOUNT=[Product(productId=3, productName=耳机, price=499.0, type=DISCOUNT)]})
Result(code=200, message=热销商品添加成功, data=null)
Result(code=200, message=商品遍历成功, data={HOT=[Product(productId=1, productName=手机, price=3999.0, type=HOT), Product(productId=4, productName=电脑, price=5999.0, type=HOT)], NEW=[Product(productId=2, productName=平板, price=2999.0, type=NEW)], DISCOUNT=[Product(productId=3, productName=耳机, price=499.0, type=DISCOUNT)]})
【实战亮点】:
-
贴合Spring Boot实战:使用@Component、@Service、@RestController等注解,利用Spring自动注入商品集合,无需手动创建,符合真实项目开发规范;
-
解耦彻底:客户端和服务层只依赖迭代器接口和聚合接口,不依赖具体集合的底层实现,新增商品集合类型(如限时秒杀商品),只需新增聚合类和迭代器类,无需修改原有代码;
-
遍历统一:无论商品集合底层是ArrayList、HashSet还是LinkedList,都通过统一的ProductIterator接口遍历,代码简洁、统一;
-
泛型优化:迭代器使用泛型,避免强制类型转换,提升代码安全性和可读性;
-
异常统一处理:服务层统一捕获异常,返回标准化响应,贴合接口开发的实际需求;
-
可维护性高:每个集合和对应的迭代器职责单一,代码清晰,后续修改某个集合的遍历逻辑,只需修改对应迭代器的代码,不影响其他逻辑。
补充:真实项目中,可结合JDK自带的Iterator接口(如List.iterator()),无需自定义迭代器接口,直接复用JDK的遍历规范,进一步简化代码,后续会在"JDK/框架应用"部分详细讲解。
五、迭代器模式在JDK/框架中的应用(面试必提)
迭代器模式的核心价值是"遍历与存储解耦、统一遍历方式",这也是它被广泛应用在JDK源码和主流Java框架中的原因,掌握这些应用场景,面试时能加分不少,还能帮助你理解框架底层设计思想。
5.1 JDK 中的迭代器模式(最常见,面试高频)
JDK内置了迭代器模式的实现,最常用的就是java\.util\.Iterator接口和java\.util\.Collection接口(聚合接口),所有Collection的实现类(ArrayList、HashSet、LinkedList等)都实现了迭代器模式,这是面试必问考点,一定要掌握。
java
// JDK内置迭代器使用示例(ArrayList为例)
import java.util.ArrayList;
import java.util.Iterator;
import java.util.List;
public class JdkIteratorTest {
public static void main(String[] args) {
List<String> list = new ArrayList<>();
list.add("Java");
list.add("Spring Boot");
list.add("MySQL");
// 1. 获取迭代器(Collection接口的iterator()方法,聚合接口的核心方法)
Iterator<String> iterator = list.iterator();
// 2. 遍历集合(统一遍历方式)
System.out.println("ArrayList遍历:");
while (iterator.hasNext()) {
String element = iterator.next();
System.out.println(element);
// 可选:删除元素(迭代器的remove()方法,避免ConcurrentModificationException)
if ("Spring Boot".equals(element)) {
iterator.remove();
}
}
// 3. 增强for循环(底层也是迭代器实现)
System.out.println("增强for循环遍历(迭代器底层):");
for (String element : list) {
System.out.println(element);
}
// 核心源码解析(ArrayList的iterator()方法)
// ArrayList内部有一个Itr内部类,实现了Iterator接口,就是具体迭代器
// public Iterator<E> iterator() {
// return new Itr();
// }
// private class Itr implements Iterator<E> {
// int cursor; // 遍历位置
// int lastRet = -1; // 上一个元素的位置
// int expectedModCount = modCount; // 用于快速失败校验
//
// public boolean hasNext() {
// return cursor != size;
// }
//
// public E next() {
// checkForComodification(); // 快速失败校验
// int i = cursor;
// if (i >= size)
// throw new NoSuchElementException();
// Object[] elementData = ArrayList.this.elementData;
// if (i >= elementData.length)
// throw new ConcurrentModificationException();
// cursor = i + 1;
// return (E) elementData[lastRet = i];
// }
// }
}
}
【核心注意点】:
-
JDK的Iterator接口是迭代器接口的标准实现,核心方法:hasNext()、next()、remove(),其中remove()方法必须在next()之后调用,否则会抛出异常;
-
Collection接口是聚合接口,定义了iterator()方法,所有Collection的实现类(ArrayList、HashSet等)都必须实现该方法,返回对应的具体迭代器;
-
快速失败(fail-fast):迭代器遍历过程中,若集合被修改(如add、remove),会抛出ConcurrentModificationException异常,目的是保证迭代器遍历的安全性;
-
增强for循环(for-each)底层是迭代器实现,本质是迭代器的简化写法,无法在遍历过程中删除元素(会抛出异常)。
5.2 框架中的迭代器模式
5.2.1 Spring 中的迭代器应用(最常用,实战必掌握)
Spring框架中,迭代器模式被广泛应用在集合遍历、Bean遍历等场景,最典型的就是org\.springframework\.util\.IteratorUtils工具类和org\.springframework\.beans\.factory\.support\.BeanDefinitionIterator。
-
IteratorUtils:提供了大量静态方法,用于操作迭代器(如将迭代器转为集合、合并迭代器、空迭代器等),简化迭代器的使用;
-
BeanDefinitionIterator:Spring容器启动时,用于遍历所有BeanDefinition(Bean的定义信息),封装了BeanDefinition的遍历逻辑,与BeanDefinition的存储结构解耦。
java
// Spring IteratorUtils工具类使用示例
import org.springframework.util.IteratorUtils;
import java.util.ArrayList;
import java.util.Iterator;
import java.util.List;
public class SpringIteratorTest {
public static void main(String[] args) {
List<String> list = new ArrayList<>();
list.add("Bean1");
list.add("Bean2");
list.add("Bean3");
Iterator<String> iterator = list.iterator();
// 1. 将迭代器转为集合
List<String> newList = IteratorUtils.toList(iterator);
System.out.println("迭代器转集合:" + newList);
// 2. 创建空迭代器(避免空指针)
Iterator<String> emptyIterator = IteratorUtils.emptyIterator();
System.out.println("空迭代器是否有下一个元素:" + emptyIterator.hasNext());
}
}
5.2.2 MyBatis 中的迭代器应用
MyBatis中,org\.apache\.ibatis\.cursor\.Cursor接口的实现类(如DefaultCursor),本质是迭代器模式的应用------Cursor用于遍历查询结果集,封装了结果集的遍历逻辑,与底层数据库查询逻辑解耦,支持分页遍历、流式遍历,提升查询效率。
六、迭代器模式高频面试考点(必背)
迭代器模式是Java后端面试高频考点,尤其是中高级岗位,重点考察JDK实现、核心优势、快速失败机制,以下4个考点必背,看完直接应对面试追问。
1. 迭代器模式的核心是什么?解决了什么问题?
必背答案:
核心:分离集合的遍历逻辑与存储逻辑,封装迭代器对象,提供统一的遍历接口,让遍历与集合底层实现解耦。
解决的问题:
-
不同集合的遍历方式不统一,代码冗余;
-
集合遍历与存储耦合,修改集合底层实现需修改遍历代码;
-
集合内部实现暴露,存在安全风险;
-
集合职责过重(既存储又遍历),违背单一职责原则。
2. JDK中的Iterator接口有哪些核心方法?remove()方法有什么注意事项?
必背答案:
核心方法:
-
hasNext():判断集合中是否还有下一个元素,返回boolean;
-
next():获取集合中的下一个元素,返回泛型对象,若没有下一个元素,抛出NoSuchElementException;
-
remove():删除当前迭代器指向的元素,必须在next()方法之后调用,否则抛出IllegalStateException;且只能删除一次当前元素,再次调用会抛出异常。
3. 迭代器的快速失败(fail-fast)和安全失败(fail-safe)有什么区别?
经典面试题,必背:
-
快速失败(fail-fast):
-
原理:迭代器遍历过程中,会校验集合的modCount(修改次数)与迭代器的expectedModCount是否一致,若不一致(集合被修改),立即抛出ConcurrentModificationException;
-
场景:JDK中的ArrayList、HashSet、LinkedList等非线程安全集合的迭代器;
-
特点:遍历效率高,不允许遍历过程中修改集合,安全性高。
-
-
安全失败(fail-safe):
-
原理:迭代器遍历的是集合的副本,而非原集合,因此遍历过程中修改原集合,不会影响迭代器的遍历;
-
场景:JDK中的CopyOnWriteArrayList、CopyOnWriteArraySet等线程安全集合的迭代器;
-
特点:遍历效率低(需复制集合),允许遍历过程中修改集合,数据可能不是最新的。
-
4. 迭代器模式的优缺点?适用场景是什么?
必背答案:
优点:
-
解耦:遍历与存储分离,客户端不依赖集合底层实现,扩展性强;
-
统一:提供统一的遍历接口,不同集合的遍历方式一致,代码简洁;
-
安全:隐藏集合内部实现,避免客户端直接操作底层存储,提升代码安全性;
-
职责清晰:集合管存储,迭代器管遍历,符合单一职责原则,维护成本低。
缺点:
-
增加类的数量:每个集合都需要对应一个迭代器,可能导致类的数量增多;
-
遍历效率:安全失败的迭代器(如CopyOnWriteArrayList),因复制集合,遍历效率较低;
-
无法反向遍历:默认的Iterator只能正向遍历,如需反向遍历,需额外实现(如ListIterator)。
适用场景:
-
需要统一遍历不同结构的集合(如ArrayList、HashSet、自定义集合);
-
需要隐藏集合内部实现,避免客户端直接操作底层存储;
-
集合的遍历逻辑复杂,需要单独封装,提升代码可维护性;
-
团队协作开发,需要统一遍历规范,减少代码冗余。
七、总结
迭代器模式是Java后端开发必掌握的解耦神器,核心思想就是"遍历与存储分离",通过封装迭代器对象,提供统一的遍历接口,解决不同集合遍历不统一、耦合度高的痛点。
新手学习从自定义迭代器入手,理解核心角色(迭代器接口、具体迭代器、聚合接口、具体聚合)和执行流程;实战开发中,优先复用JDK自带的Iterator接口,结合Spring、MyBatis等框架的迭代器应用,简化代码;面试重点掌握JDK迭代器实现、快速失败与安全失败的区别、优缺点和适用场景。
实际开发中,简单场景可直接使用JDK内置迭代器(如ArrayList.iterator()),复杂场景(如自定义集合、多类型集合统一遍历)可自定义迭代器,灵活选择,让代码更优雅、更可扩展。