从上图可以看出,当执行 e.printStackTrace() 和 finally 输出信息时,使用的并不是同一个对象。finally 使用的是标准输出流:System.out,而 e.printStackTrace() 使用的却是标准错误输出流:System.err.println,它们执行的效果等同于:
public static void main(String[] args) { System.out.println("我是标准输出流"); System.err.println("我是标准错误输出流"); }
而以上代码执行结果的顺序也是随机的,而产生这一切的原因,我们或许可以通过标准错误输出流(System.err)的注释和说明文档中看出:
我们简单的对以上的注释做一个简单的翻译:
“标准”错误输出流。该流已经打开,并准备接受输出数据。通常,此流对应于主机环境或用户指定的显示输出或另一个输出目标。按照惯例,即使主要输出流(out 输出流)已重定向到文件或其他目标位置,该输出流(err 输出流)也能用于显示错误消息或其他信息,这些信息应引起用户的立即注意。
从源码的注释信息可以看出,标准错误输出流(System.err)和标准输出流(System.out)使用的是不同的流对象,即使标准输出流并定位到其他的文件,也不会影响到标准错误输出流。那么我们就可以大胆的猜测:二者是独立执行的,并且为了更高效的输出流信息,二者在执行时是并行执行的,因此我们看到的结果是打印顺序总是随机的。
为了验证此观点,我们将标准输出流重定向到某个文件,然后再来观察 System.err 能不能正常打印,实现代码如下:
public static void main(String[] args) throws FileNotFoundException { // 将标准输出流的信息定位到 log.txt 中 System.setOut(new PrintStream(new FileOutputStream("log.txt"))); System.out.println("我是标准输出流"); System.err.println("我是标准错误输出流"); }