1. 迭代器模式概述
1.1 什么是迭代器模式?
迭代器模式(Iterator Pattern)是一种行为设计模式,它用于提供一种方法顺序访问集合对象中的各个元素,而无需暴露其内部结构。其核心思想是通过迭代器对象来遍历集合,使得客户端代码不必关注集合的具体实现方式。
1.2 迭代器模式的优点
封装性:隐藏集合的内部表示,仅通过迭代器提供访问方式。
一致性:统一不同集合的访问方式,提高代码的可读性和可维护性。
支持多种遍历方式:可以实现正序、倒序、懒加载等不同遍历方式。
2. 在 Java 文件读取中的应用
在实际应用中,文件读取通常需要处理大量数据,采用迭代器模式可以有效优化内存使用,提高性能。本文展示了两种基于迭代器模式的文件读取方式:一次性加载 和 懒加载。
2.1 一次性加载(UserFile
)
package com.xxx;
import java.io.File;
import java.io.IOException;
import java.nio.file.Files;
import java.util.Iterator;
import java.util.List;
import java.util.NoSuchElementException;
import java.util.stream.Collectors;
public class UserFile implements Iterable<User> {
private final File file;
public UserFile(File file) {
this.file = file;
}
@Override
public Iterator<User> iterator() {
return new UserIterator();
}
class UserIterator implements Iterator<User> {
List<User> userList = loadUsersFromFile();
int cursor = 0;
private List<User> loadUsersFromFile() {
try {
long beforeMemory = usedMemory();
List<User> users = Files.readAllLines(file.toPath()).stream().map(line -> {
String substring = line.substring(1, line.length() - 1);
String[] split = substring.split(",");
return new User(split[0], Integer.parseInt(split[1]));
}).collect(Collectors.toList());
long afterMemory = usedMemory(); // 记录加载后内存
System.out.println("一次性加载内存占用:" + (afterMemory - beforeMemory) / (1024 * 1024) + " MB");
return users;
} catch (IOException e) {
e.printStackTrace();
return null;
}
}
@Override
public boolean hasNext() {
return cursor != userList.size();
}
@Override
public User next() {
if(cursor >= userList.size()) {
throw new NoSuchElementException();
}
int cursorIndex = cursor;
cursor++;
return userList.get(cursorIndex);
}
}
private long usedMemory() {
Runtime runtime = Runtime.getRuntime();
return runtime.totalMemory() - runtime.freeMemory(); // 计算当前堆内存使用情况
}
}
特点:
一次性读取整个文件并存入
List<User>
,然后通过Iterator
顺序访问。适用于小文件,因为所有数据都会存入内存。
加载时占用较大内存,但遍历速度快。
2.2 懒加载(LazyUserFile
)
package com.xxx;
import java.io.BufferedReader;
import java.io.File;
import java.io.IOException;
import java.nio.file.Files;
import java.util.Iterator;
import java.util.NoSuchElementException;
public class LazyUserFile implements Iterable<User>{
private final File file;
public LazyUserFile(File file) {
this.file = file;
}
@Override
public Iterator<User> iterator() {
return new LazyUserIterator();
}
class LazyUserIterator implements Iterator<User>{
private BufferedReader reader;
private String nextLine;
private long beforeMemory;
public LazyUserIterator() {
try {
beforeMemory = usedMemory();
reader = Files.newBufferedReader(file.toPath());
nextLine = reader.readLine();
} catch (IOException e) {
e.printStackTrace();
nextLine = null;
}
}
@Override
public boolean hasNext() {
return nextLine != null;
}
@Override
public User next() {
if (nextLine == null) {
throw new NoSuchElementException();
}
String line = nextLine;
nextLine = readNextLine();// 读取下一行
if(nextLine == null) {
long afterMemory = usedMemory();
System.out.println("懒加载内存占用:" + (afterMemory - beforeMemory) / (1024 * 1024) + " MB");
try {
reader.close();
} catch (IOException e) {
throw new RuntimeException(e);
}
}
return parseUser(line);
}
private String readNextLine() {
try {
return reader.readLine();
} catch (IOException e) {
e.printStackTrace();
return null;
}
}
private User parseUser(String line) {
String substring = line.substring(1, line.length() - 1);
String[] split = substring.split(",");
return new User(split[0], Integer.parseInt(split[1]));
}
}
private long usedMemory() {
Runtime runtime = Runtime.getRuntime();
return runtime.totalMemory() - runtime.freeMemory(); // 计算当前堆内存使用情况
}
}
特点:
逐行读取文件,每次只在内存中存储一个
User
。适用于大文件,大幅减少内存占用。
遍历速度稍慢,因为每次都要从文件读取数据。
3. 两种方式的对比
4. 总结
迭代器模式为遍历集合提供了一种 统一的方式,使代码更加解耦。
一次性加载(
UserFile
) 适合小文件,懒加载(LazyUserFile
) 适合大文件。合理使用迭代器模式,可以优化 Java 应用的内存占用,提升程序性能。