FilterInputStream 和 FilterOutputStream 是 Java I/O 中装饰器模式的典型实现,通过包装已有流来增强功能:前者在输入流上叠加处理逻辑(如计数、缓冲),后者在输出流上插入干预点(如校验、缓冲),均基于委托机制,支持链式组合与单一职责扩展。

FilterInputStream 和 FilterOutputStream 是 Java I/O 中典型的装饰器模式实现,它们本身不直接处理底层数据读写,而是包装已有流,在其基础上添加新功能或增强行为。
FilterInputStream:在输入流上叠加处理逻辑
它继承 InputStream,构造时接收一个 InputStream 实例,所有读操作(如 read()、skip()、available())默认委托给被包装的流。扩展时只需重写需要定制的方法即可。
- 例如,CountingInputStream 可统计已读字节数:重写 read() 方法,在调用 super.read() 后递增计数器
- BufferedInputStream 就是标准实现——它内部维护缓冲区,重写 read() 实现批量读取+按需返回,提升性能
- 注意:mark() / reset() 行为需同步维护包装流的状态,否则可能失效;若底层流不支持 mark,子类也不应声称支持
FilterOutputStream:在输出流上插入处理环节
类似地,它包装 OutputStream,write()、flush()、close() 等方法默认转发。扩展的关键在于控制“数据写出前”或“写出后”的干预点。
- BufferedOutputStream 在 write() 中先写入内部缓冲区,满时才 flush 到底层流
- CheckedOutputStream 可在 write() 中实时更新校验和(如 CRC32),便于后续验证完整性
- 务必确保 close() 正确调用 super.close(),否则底层流可能未释放资源
自定义装饰器的实用要点
写自己的 Filter 子类时,核心是明确“增强什么”和“何时介入”。不要重写无关方法,避免破坏原有语义。
- 只重写真正需要改变行为的方法;其余保持 super.xxx() 委托
- 构造函数必须接收被包装的流,并保存为 final 字段(避免空指针或替换风险)
- 如果涉及状态(如缓冲区、计数器),需考虑多线程安全——多数 Filter 流本身不保证线程安全,由使用者负责同步
- 可链式组合:new CountingInputStream(new BufferedInputStream(new FileInputStream("a.txt"))),每层专注单一职责
与其它装饰方式的区别
不同于继承(会受限于单继承),装饰器通过组合复用,更灵活。也不同于代理(Proxy),Filter 类明确聚焦 I/O 行为增强,API 设计已预留钩子(即那些可重写的方法)。
- InputStreamReader/OutputStreamWriter 是桥接模式,用于字节流与字符流转换
- Scanner 或 PrintWriter 是更高层的工具类,封装了格式化逻辑,不属于装饰器范畴
- Java 8 后部分场景可用 Stream API + 函数式接口替代简单过滤,但底层仍常依赖 FilterXXX
Java免费学习笔记:立即使用
解锁 Java 大师之旅:从入门到精通的终极指南











