Java中重定向System.out到ByteArrayOutputStream失效原因排查
问题分析:静态引用System.out导致测试输出失效
问题代码
被测试类 Bla
class Bla { private static final Consumer<String> OUTPUT = System.out::println; public void print() { printStuff(OUTPUT); } public void printStuff(Consumer<String> consumer) { consumer.accept("Bla"); } }
测试代码
Bla bla = new Bla(); ByteArrayOutputStream baos = new ByteArrayOutputStream(); final PrintStream standardOut = System.out; System.setOut(new PrintStream(baos)); bla.print(); LOG.info(baos.toString().trim()); // 无输出 System.setOut(standardOut);
原因解释
核心问题是静态常量的初始化时机:
OUTPUT是static final修饰的常量,它会在Bla类加载阶段就完成初始化,此时System.out::println会直接绑定到当时的System.out实例(也就是默认的控制台输出流)。- 测试代码中调用
System.setOut(new PrintStream(baos))是在类加载之后,这时候OUTPUT的引用已经固定,不会跟随System.out的后续替换而更新。所以调用bla.print()时,输出还是会写入最初的控制台流,而非你替换后的baos流,导致baos.toString()没有内容。
而将OUTPUT内联(直接写printStuff(System.out::println))时,System.out::println是在print()方法调用时才会解析绑定,此时System.out已经被替换为baos对应的流,所以输出会正常写入baos,能捕获到内容。
可行的解决方式
- 移除
OUTPUT静态常量,每次调用时直接使用System.out::println,确保绑定的是当前的System.out实例。 - 将
OUTPUT改为非静态成员,在Bla实例化时再初始化,保证引用的是实例创建时的System.out。 - 优化代码设计,直接通过
printStuff方法的参数注入输出消费者,测试时可以直接传入针对baos的消费者,无需替换全局的System.out。
内容的提问来源于stack exchange,提问作者Shivani S
相关产品推荐
相关产品推荐

