PushbackReader 是 Java 中支持字符级回退的输入流装饰器,通过缓冲区实现 unread() 操作,适用于语法解析等需上下文回溯的场景,但缓冲区容量有限且需避免重复回退或溢出。

PushbackReader 是 Java IO 中专为“读取后可回退”设计的字符输入流装饰器,它在语法解析(如词法分析、自定义配置文件读取、简单脚本解释器)中非常实用——当读到某个字符后发现需要重新判断上下文时,能把它“推回去”,下次 read() 还能再读到。
核心机制:缓冲区 + 一次回退能力
PushbackReader 内部维护一个固定大小的字符缓冲区(默认 1 字节,构造时可指定),调用 unread(int c) 或 unread(char[] buf) 会把字符压入缓冲区头部;后续 read() 优先从缓冲区取,缓冲区空了才从底层 Reader 继续读。注意:只能回退已读出、尚未被消费的字符,且不能超过缓冲区容量。
常见误用:连续 unread() 多次但缓冲区太小 → 抛 IOException("Push back buffer is full")。
典型语法解析场景:识别标识符与关键字
比如解析形如 if (x > 0) { ... } 的简单表达式,需区分关键字 if 和普通标识符 info。读到 'i' 后不能立刻断定是 if,得继续看后面是否为 'f' 和非字母数字字符:
立即学习“Java免费学习笔记(深入)”;
- 读取第一个字符
c1 = read() - 若
c1 == 'i',再读c2 = read() - 若
c2 == 'f'且下一个字符c3是空白或括号等分隔符,则确认为关键字if - 否则,把
c2和(如果已读了c3)c3全部unread()回去,按标识符处理c1开头的整个名字
安全使用要点
避免因缓冲区溢出或状态混乱导致解析错误:
- 构造时显式指定足够缓冲区大小,例如
new PushbackReader(reader, 4)可支持最多回退 4 个字符(匹配while、return等长关键字) - 每次
unread()前确保未超限,可用available()判断剩余空间(但注意该方法返回的是底层流剩余+缓冲区空闲总和,不精确反映 pushback 容量) - 不要对同一个字符重复
unread();也不要在close()后调用unread() - 异常处理中记得
unread()已读但未确认的字符,防止丢失输入
对比替代方案
不用 PushbackReader 也能实现回退,但更繁琐:
- 用
StringReader(new String(charArray))配合索引手动管理位置 → 灵活但内存开销大、线程不安全 - 用
BufferedReader.mark()/reset()→ 要求底层支持 mark,且mark()位置固定、不能动态调整,不适合多层嵌套回退 - Java 14+ 的
Scanner提供useDelimiter()和正则匹配,适合规则文本,但无法精细控制单字符级回溯逻辑
PushbackReader 在轻量、可控、字符级回退场景下仍是简洁可靠的选择。


















