【问题标题】:Strange behavior with printStackTrace()printStackTrace() 的奇怪行为
【发布时间】:2015-09-24 21:38:54
【问题描述】:

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

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

【问题讨论】:

    标签: exception java.util.scanner printstacktrace


    【解决方案1】:

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

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

    【讨论】:

      【解决方案2】:

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

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

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

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

      【讨论】:

      • e.printStackTrace(System.out) 工作得很好,但是 eclipse 没有以红色显示文本。并不重要,因为该程序不打算在 Eclipse 中运行,但如果可能的话,我仍然希望刷新解决方案能够正常工作,那么我该怎么做呢?我尝试在e.printStackTrace()之后直接添加System.out.flush(); System.err.flush();,但问题仍然存在。
      • printStackTrace 之前和之后确实过度冲洗,我可以得到它与Thread.sleep(100) 一致(这是第一个链接问题suggests 的另一个答案)
      【解决方案3】:

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

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

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

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

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

      解决方案:

      您应该尝试通过设计代码的方式来解决这个问题,即何时打印并不重要。

      【讨论】:

        猜你喜欢
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 2021-06-08
        • 2015-07-20
        • 2010-10-03
        • 2021-07-12
        • 2013-10-04
        • 2019-01-23
        相关资源
        最近更新 更多