2

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输出总是按预期出现或出现在上面的第二个输出中 - 在第二行的开头。

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

4

3 回答 3

4

printStackTrace,根据文档,打印到标准错误流

public void printStackTrace() – 将此 throwable 及其回溯打印到标准错误流。

...这是System.err。然后你正在写信给System.out. 这两个是不同的流,因此会在不同的时间刷新到实际输出。保留代码原样,它相当于这个问题中概述的问题

要解决此问题,您可以手动刷新输出流或将异常打印到System.out而不是System.err. 您可以使用printStackTrace 的变体,它接受PrintStream带有标准输出的 a 作为参数:e.printStackTrace(System.out);

于 2015-07-07T12:03:19.560 回答
1

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

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

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

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

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

解决方案:

您应该尝试通过以与何时打印无关紧要的方式设计代码来解决此问题。

于 2015-07-07T12:55:26.587 回答
0

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

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

于 2015-07-07T12:02:01.927 回答