pushbackreader 是 java 中支持字符回退的装饰器,用于预读和回退场景;它包装普通 reader,通过 unread() 将已读字符推回缓冲区,解决单向读取限制,适用于词法分析等轻量解析任务。

PushbackReader 是 Java I/O 中一个支持“回退一个或多个字符”的字符流装饰器,特别适合需要预读(peek)和回退(unget)的文本解析场景,比如实现简易词法分析器、自定义配置文件解析器或表达式求值器。
为什么需要 PushbackReader?
普通 Reader(如 InputStreamReader)只能单向读取,一旦调用 read() 消耗了字符,就无法退回。而很多解析逻辑依赖“先看一眼下一个字符再决定如何处理”——例如:
- 遇到
'-'后,需判断是减号还是负号(要看后面是否跟数字) - 读到引号
",需进入字符串模式,但若下一个是'\'则可能是转义 - 跳过空白后想确认下一个非空字符是否为分隔符
这时 PushbackReader 提供的 unread(int) 或 unread(char[]) 就能将已读字符“塞回去”,让后续读取重见它们。
基本用法:构造与回退操作
它必须包装一个底层 Reader,并可指定缓冲区大小(默认为 1):
Reader source = new StringReader("abc123");
PushbackReader pbr = new PushbackReader(source, 4); // 缓冲区最多存 4 个字符
常用操作:
Java JDK 25 来自 OpenJDK 官方归档,版本为 JDK 25,本条下载地址已指向官方 Windows x64 zip 安装包直链,适合调试旧项目或兼容旧版 Java 运行环境。
-
int c = pbr.read():读取一个字符(返回 int,-1 表示 EOF) -
pbr.unread(c):把一个字符推回缓冲区(下次read()会先返回它) -
pbr.unread(new char[]{'x','y'}):一次推回多个字符(按逆序入栈) -
pbr.unread(buf, off, len):推回字符数组片段
⚠️ 注意:推回字符数不能超过构造时指定的缓冲区大小,否则抛 IOException(“Push back buffer is full”)。
典型解析示例:跳过空白后安全 peek 下一个字符
下面是一个安全读取“下一个非空白字符”的工具方法:
public static int readNonWhitespace(PushbackReader pbr) throws IOException {
int c;
while ((c = pbr.read()) != -1) {
if (!Character.isWhitespace((char) c)) {
return c; // 返回首个非空白字符
}
}
return -1; // EOF
}
// 使用示例:
StringReader sr = new StringReader("
+123");
PushbackReader pbr = new PushbackReader(sr);
int first = readNonWhitespace(pbr); // 返回 '+',内部已消耗所有空白
System.out.println((char)first); // 输出 '+'
// 若还想保留 '+' 供后续解析器使用,可在返回前 unread:
// pbr.unread(first);
这个模式避免了“读多了再吐出来”的混乱,也比手动维护临时变量更清晰。
实用技巧与注意事项
- 缓冲区大小要合理:解析器最多需要回退几个字符,就设多大(如支持最长 3 字符关键字 + 1 个分隔符 → 设 4)
-
unread 后不要跨方法丢失引用:确保
PushbackReader实例在回退后仍被同一解析逻辑使用,别把它传给不兼容的其他 Reader 方法 -
异常处理要覆盖 unread:如果在
unread()前发生异常,可能已部分读取但未回退,建议用 try-with-resources 管理底层流,并在关键路径加日志 - 不替代状态机:它解决的是“字符级回退”,复杂语法(如嵌套括号、引号配对)仍需配合解析状态管理
它不是万能的,但在轻量级、基于字符流的解析任务中,是让代码更简洁、逻辑更贴近自然语言描述的利器。
Java免费学习笔记:立即使用
解锁 Java 大师之旅:从入门到精通的终极指南










