一个 System.out 与 Throwable.printStackTrace() 输出信息顺序错乱的问题

昨天天遇到了一个 System.outThrowable.printStackTrace() 输出信息顺序错乱的问题。

现场还原

首先我调用 System.out 输出普通字符串

Time: 0.2
------------------------
!!!FAILURES!!!
Test Results:
 Failures: 1 Errors: 1
There was 1 error:
0) test.MathTest.ok
There was 1 failure:
0) test.MathTest.add expected:"1" but was:"2"

然后再调用 Throwable.printStackTrace() 输出异常信息

java.lang.NoSuchMethodException: test.MathTest.ok()
    at java.lang.Class.getMethod(Class.java:1786)
    at com.okada.junit.TestCase.runTest(TestCase.java:51)
    at com.okada.junit.TestCase.run(TestCase.java:31)
    at com.okada.junit.TestSuite.run(TestSuite.java:23)
    at com.okada.junit.TestRunner.run(TestRunner.java:44)
    at com.okada.junit.TestRunner.main(TestRunner.java:37)
    at test.MathTest.main(MathTest.java:31)

正常来说应该能得到如下输出内容

Time: 0.2
------------------------
!!!FAILURES!!!
Test Results:
 Failures: 1 Errors: 1
There was 1 error:
0) test.MathTest.ok
There was 1 failure:
0) test.MathTest.add expected:"1" but was:"2"
java.lang.NoSuchMethodException: test.MathTest.ok()
    at java.lang.Class.getMethod(Class.java:1786)
    at com.okada.junit.TestCase.runTest(TestCase.java:51)
    at com.okada.junit.TestCase.run(TestCase.java:31)
    at com.okada.junit.TestSuite.run(TestSuite.java:23)
    at com.okada.junit.TestRunner.run(TestRunner.java:44)
    at com.okada.junit.TestRunner.main(TestRunner.java:37)
    at test.MathTest.main(MathTest.java:31)

但是有时候多运行几次代码会得到错乱的信息

Time: 0.2
    at java.lang.Class.getMethod(Class.java:1786)
------------------------
    at com.okada.junit.TestCase.runTest(TestCase.java:51)
!!!FAILURES!!!
Test Results:
    at com.okada.junit.TestCase.run(TestCase.java:31)
 Failures: 1 Errors: 1
    at com.okada.junit.TestSuite.run(TestSuite.java:23)
There was 1 error:
    at com.okada.junit.TestRunner.run(TestRunner.java:44)
0) test.MathTest.ok
    at com.okada.junit.TestRunner.main(TestRunner.java:37)
There was 1 failure:
    at test.MathTest.main(MathTest.java:31)
0) test.MathTest.add expected:"1" but was:"2"

System.outThrowable.printStackTrace() 的输出内容混在一起了,没有按照顺序来输出

原因

问了别人,说是因为 System.outSystem.err 的输出顺序问题。于是查看了下 Throwable.printStackTrace() 的源码。发现 Throwable.printStackTrace() 会调用 System.err 进行内容输出

public void printStackTrace() {
    printStackTrace(System.err);
}

public void printStackTrace(PrintStream s) {
    printStackTrace(new WrappedPrintStream(s));
}

private void printStackTrace(PrintStreamOrWriter s) {
    // ...
}

再查看网上的解释,System.out 是有缓冲区的,JVM 和操作系统会等待缓冲区中的内容达到一定的大小再输出内容。而 System.err 的话,是没有缓冲区这种东西,有内容就立刻输出。所以造成了 System.outThrowable.printStackTrace() 的输出内容混在一起了。这就是原因。

如何解决

根据 Throwable.printStackTrace() 的源码

public void printStackTrace() {
    printStackTrace(System.err);
}

public void printStackTrace(PrintStream s) {
    printStackTrace(new WrappedPrintStream(s));
}

private void printStackTrace(PrintStreamOrWriter s) {
    // ...
}

只需要调用 printStackTrace(PrintStream s) 传入 System.err 即可,也就是调用 Throwable.printStackTrace(System.err)

这样输出内容再也不会顺序错乱了。

你可能感兴趣的:(一个 System.out 与 Throwable.printStackTrace() 输出信息顺序错乱的问题)