如何保持sysout和syserr流不混合?

在我的代码库中是(非常简化)以下:

public static void main (String[] args) { System.out.println("Starting application"); try { System.out.println("About to validate"); validate(args); catch (Exception e) { e.printStackTrace(); } } public static void validate(String[] args) { System.out.println("Your first arg is " + args[0]); if (someProblemWith(args)) { System.out.println("Your args are wrong. It should be: ..."); throw new BadArgsException(e); } } 

哪个工作正常。 请注意,上面的示例代码是设计的,只是为了在exception和堆栈跟踪打印之前显示多个日志语句。 这通常意味着我的上一个日志记录语句在堆栈跟踪输出的中间丢失。 是否有一种优雅的方式要求e.printStackTrace()语句等到System.out完成其工作? 我基本上在寻找堆栈跟踪是发生错误时打印的最后一件事。 这是我上面程序的示例输出:

  java.lang.Throwable .... at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method) at sun.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:39) at sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:25) Your args are wrong. It should be: ... at java.lang.reflect.Method.invoke(Method.java:597) at org.eclipse.jdt.internal.jarinjarloader.JarRsrcLoader.main(JarRsrcLoader.java:56) 

调用e.printStackTrace(System.out); 。 或者,如果只需要它进行调试,可以将进程的输出和错误从命令行中分离出来: .... 1>output.log 2>error.log

您看到在System.out.println()语句之间打印堆栈跟踪的原因是因为System.out是缓冲的,而System.err (由堆栈跟踪使用)是无缓冲的。

如果希望文本按照发生事件的确切顺序显示,则需要“解除” System.out “缓冲”。 最简单的方法是在那里使用System.err而不是System.out

否则,在catch子句中发生堆栈跟踪之前调用System.out.flush()

选项2:使用Logger类。

选项3:实现自己的“缓冲区”。 换句话说,首先将所有内容写入您自己的缓冲区,包括堆栈跟踪(使用.toString()或者您希望的话),然后在catch刷新您自己的缓冲区。 (这有点多余,因为无论如何你只需要刷新System.out )。

– == –

来自评论

当然。 Logger类可用于创建更强大和详细的日志记录体验。 这通常是在应用程序中完成的操作。 Logger类的一个实例是从Logger类中获取的(它是一个单例),将从中使用的类作为参数。 然后使用.log()方法将消息记录到它。 关于Logger类的Logger是你可以在它上面设置级别(例如DEBUGWARN …),然后你就可以过滤/显示你想要的东西了。 然后,“log”消息以统一的方式显示在控制台中,通常采用以下格式:

2010-11-23 14:45:32,032 DEBUG [MyClass] Your message

以上格式来自log4j ,但您可以使用标准Java Logger 。 输出应该类似,可能会少一些。 但我确信它可以配置。