好吧,如果您查看fillInStackTrace
,您会注意到该方法是synchronized
。同步在 Java(或任何语言)中被认为是一项相当昂贵的操作,因为它需要获取和释放监视器。
另外,您应该注意,Throwable
返回的 fromfillInStackTrace
仅记录有关调用堆栈在调用时的堆栈帧的信息fillInStackTrace
。此信息直接从 JVM 收集,然后转换为再次消耗资源的对象表示。(最终,fillInStackTrace
委托给一个native
扫描调用线程的当前调用堆栈的方法。)
但是,您应该主要考虑要在日志中显示的内容并根据该标准来决定。当您显式调用fillInStackTrace
时,当前调用堆栈将出现在您的日志中。这意味着您将不再看到到达您的块的更深try
的调用堆栈(考虑您的示例)。
毕竟,除非您明确需要通过(2)获得的信息,否则您应该始终使用变体(1 ) 。我无法自发地想到解决方案(2)有意义的标准日志记录范围内的示例。但是,当您编写某种框架并且想要清除一些与异常无关的顶部堆栈条目时,您可以使用(2)来消除堆栈跟踪中的噪音:例如,您可能正在使用某种ExceptionFactory
为您创建抛出的异常。然后,您不希望堆栈跟踪显示这些工厂方法的堆栈帧,因为它们与错误无关,并且会使尝试调试的用户感到困惑。fillInStackTrace
因此,您将在收到工厂的异常后通过调用手动填充堆栈跟踪。
看这个例子,直观地了解这两个调用的区别:
class Example {
public static void main(String[] args) {
try {
outerFunction();
}
catch (Throwable e) {
System.err.println("Outside:");
e.printStackTrace();
}
}
static void outerFunction() throws Throwable {
try {
innerFunction();
}
catch(Exception e) {
System.err.println("Inside:");
e.printStackTrace();
throw e.fillInStackTrace();
}
}
static void innerFunction() {
throw new RuntimeException("A custom exception");
}
}
将调用这两个不同的堆栈跟踪:
Inside:
java.lang.RuntimeException: A custom exception
at Example.innerFunction(Example.java:21)
at Example.outerFunction(Example.java:13)
at Example.main(Example.java:19)
Outside:
java.lang.RuntimeException: A custom exception
at Example.outerFunction(Example.java:13)
at Example.main(Example.java:19)