printStackTrace() 的奇怪行为

Strange behavior with printStackTrace()

printStackTrace() 就像在等待输入后在自己的线程中运行一样。这是我的代码:

try {
    new Scanner(System.in).nextLine();
    throw new Exception();
} catch (Exception e) {
    e.printStackTrace();
}
System.out.print("STUFF");

我有时会得到预期的输出(最后有 STUFF),但有时我会得到这个:

blabla // the scanner input
java.lang.ExceptionSTUFF
    at Test.main(Test.java:7)

有时这样:

blabla
java.lang.Exception
STUFF   at Test.main(Test.java:7)

System.in.read() 替换扫描仪会产生相同的结果。完全删除该行会产生预期的结果。在我注意到这个问题的实际程序中,堆栈跟踪要长得多,并且 STUFF 输出总是按预期或上面的第二个输出出现 - 在第二行的开头。

这是什么原因造成的,我该如何解决?

这是将内容打印到控制台的本质。一切,标准输出,标准错误等都被假脱机打印到控制台,但是因为 java 本质上是多线程的,所以不能保证这些项目被添加到打印队列的顺序。

多线程可以做时髦的事情!

printStackTrace,根据文档,prints to the standard error stream

public void printStackTrace() – Prints this throwable and its backtrace to the standard error stream.

...即 System.err。那么你正在写信给 System.out。这两个是不同的流,因此在不同的时间刷新到实际输出。保留代码原样,它等同于 this question.

中概述的问题

要解决此问题,您可以手动刷新输出流或将异常打印到 System.out 而不是 System.err。您可以将 variant of printStackTrace that accepts a PrintStream 与标准输出一起用作参数:e.printStackTrace(System.out);

这实际上根本不是什么奇怪的行为; Java 旨在以这种方式工作。在大多数情况下,这是一个我们都喜欢拥有的功能,它使我们的代码 运行 比我们实际编写的代码更高效。 'it' 指的是 JVM 旨在将我们的代码重新安排和优化为更好的字节码,这比我们普通开发人员甚至无法实现的更好。

你可以这样看一点; Java 是我们在整个代码中使用的一种框架,它将以最有效的方式(至少已对其进行编程)完成我们想要的事情。 Java API 是我们正在使用的 Java 框架的 API。

并将其与您的代码联系起来;您正在初始化两个流,两个缓冲流,一个是 System.out,一个是 printStackTrace()。当您执行您的代码时,Java 将重新安排您的代码并将其线程化到 运行 最佳 Java 可以做到的。这意味着首先完成的流将打印到控制台。

Java 对打印的内容没有任何价值,这是我们人类拥有的价值;我们喜欢按特殊顺序阅读东西。这就是为什么 Java 对我们开发人员来说是一个挑战,要编写不关心何时执行的线程安全代码;给定相同的输入,它应该总是 return 相同的输出。

由于您的 System.out 流比堆栈跟踪流的打印速度更快,因此它可能总是先于堆栈跟踪打印,因为它们是 缓冲 ​​ 流。缓冲流需要时间来缓冲,这既是线程又是不同的耗时。为什么 Java 不给你先完成的流并释放那个线程和 CPU?

解决方案:

您应该尝试通过以一种无关紧要的方式设计您的代码来解决这个问题。