Throwable.printStackTrace()将堆栈跟踪写入System.err PrintStream。 System.err流和JVM进程的底层标准“错误”输出流可以重定向
>调用System.setErr(),改变System.err指向的目的地。
>或通过重定向进程的错误输出流。错误输出流可以重定向到文件/设备
>其内容可能被人员忽视,
>文件/设备可能无法记录旋转,推断在归档文件/设备的现有内容之前需要进程重新启动以关闭打开的文件/设备句柄。
>或者文件/设备实际上丢弃写入它的所有数据,如/ dev / null的情况。
从上述推断,调用Throwable.printStackTrace()构成有效(不好/很好)异常处理行为,只有
>如果你没有在整个应用程序的生命周期重新分配System.err,
>如果在应用程序运行时不需要日志轮换,
>如果接受/设计的应用程序的日志实践是写入System.err(和JVM的标准错误输出流)。
在大多数情况下,不满足上述条件。可能不知道在JVM中运行的其他代码,并且不能预测日志文件的大小或进程的运行时间,而良好设计的日志实践将围绕编写“机器可解析”日志文件在记录器中的优选但可选的特征),以帮助支持。
最后,应该记住,Throwable.printStackTrace()的输出肯定会与写入System.err的其他内容(如果两者都重定向到同一文件/设备,甚至可能是System.out)交织。这是一个人必须处理的烦恼(对于单线程应用程序),因为异常的数据在这样的事件中不容易解析。更糟的是,多线程应用程序很可能会产生非常混乱的日志,因为Throwable.printStackTrace()不是线程安全的。
当多个线程同时调用Throwable.printStackTrace()时,没有同步机制来同步将堆栈跟踪写入System.err。解决此问题实际上需要您的代码在与System.err(以及System.out,如果目标文件/设备是相同的)相关联的监视器上同步,并且这是相当沉重的价格来支付日志文件的健全性。例如,ConsoleHandler和StreamHandler类负责将日志记录附加到控制台,在由java.util.logging提供的日志记录工具中;发布日志记录的实际操作是同步的 – 尝试发布日志记录的每个线程还必须获取与StreamHandler实例关联的监视器上的锁。如果希望使用System.out / System.err具有非交叉日志记录的同样保证,则必须确保相同 – 消息以可串行化的方式发布到这些流。
考虑到上述所有情况,以及Throwable.printStackTrace()实际上很有用的非常有限的情况,它经常证明调用它是一个坏的做法。
扩展前面段落中的参数,使用Throwable.printStackTrace与向控制台写入的记录器结合使用也是一个不好的选择。这部分是由于记录器在不同的监视器上同步的原因,而您的应用程序(可能,如果不想交叉日志记录)在不同的监视器上同步。当您在应用程序中使用两个不同的记录器写入相同的目标时,参数也是很好的。