Java中使用PrintStream对象打印与System.out.println()有何区别
Java中两种PrintStream打印方式的本质区别
你测试时观察不到输出差异是正常场景下的表现,二者核心区别不在最终输出内容,而在底层对象逻辑、配置、资源开销层面,具体如下:
两种写法的代码示例
第一种是自行创建PrintStream包装标准输出:
PrintStream ps = new PrintStream(System.out); ps.println("Printing");
第二种是直接调用全局标准输出实例的打印方法:
System.out.println("Printing");
核心差异点
- 对象实例属性不同
System.out本身就是JVM启动阶段全局初始化的单例PrintStream对象,默认绑定控制台标准输出流。自行new PrintStream(System.out)是在已有的全局标准输出流之上,额外创建了一个独立的PrintStream包装对象,本质是给同一个输出管道套了一层新的外壳,没有改变最终输出的目标端点;直接调用System.out.println()是直接操作JVM持有的原生全局实例,没有额外创建包装对象。 - 默认刷新策略不同
你用单参数构造方法创建的PrintStream实例,默认关闭自动行刷新:只有当缓冲区写满、手动调用flush()方法、流关闭时,才会把缓冲区里的内容推送到控制台。如果程序异常退出、多线程抢占输出资源,很容易出现打印内容丢失的问题。而JVM初始化的全局System.out实例默认开启自动行刷新,每次调用println写入换行符时,会立刻把缓冲区内容强制刷到控制台,不会出现内容滞留缓冲区的问题。 - 资源风险与开销不同
自行创建的PrintStream包装对象如果调用close()方法,会连带把它包装的底层System.out全局流一并关闭,后续整个程序所有调用System.out.println的代码都会直接失效,无法打印任何内容。同时每次new新的PrintStream包装对象都会产生不必要的内存开销,频繁创建会增加GC压力;直接使用全局的System.out实例不需要额外创建对象,也不存在误关全局流的风险,JVM退出时会自动回收该流资源。
为什么测试时看不到差异
你测试时两种写法输出效果一致,是因为单线程顺序执行场景下,要么打印内容刚好填满缓冲区触发了自动刷出,要么程序正常退出时JVM会统一把所有流的剩余缓冲区内容全部刷出,没有触发缓冲区滞留、流被误关、异常退出丢内容的边界场景,所以肉眼观察不到任何区别。
如果你确实需要包装System.out做自定义打印逻辑,记得用双参数构造方法
new PrintStream(System.out, true)开启自动行刷新,同时不要调用close方法关闭这个包装对象,避免影响全局标准输出。
内容的提问来源于stack exchange,提问作者NoNoNo
相关产品推荐
相关产品推荐

