这可能是一个非常幼稚的问题。
我曾经相信Throwable
Java中的 a总是包含堆栈跟踪。这是正确的吗?
现在看起来我在没有堆栈跟踪的情况下捕获了异常。是否有意义?是否可以在没有堆栈跟踪的情况下捕获异常?
这可能是一个非常幼稚的问题。
我曾经相信Throwable
Java中的 a总是包含堆栈跟踪。这是正确的吗?
现在看起来我在没有堆栈跟踪的情况下捕获了异常。是否有意义?是否可以在没有堆栈跟踪的情况下捕获异常?
可以在没有堆栈跟踪的情况下在 Java 中捕获 Throwable 对象:
Throwable(String message, Throwable cause, boolean enableSuppression,boolean writableStackTrace)
使用指定的详细消息、原因、启用或禁用抑制以及启用或禁用可写堆栈跟踪构造一个新的 throwable 。
public Throwable fillInStackTrace()
填写执行堆栈跟踪。此方法在此 Throwable 对象中记录有关当前线程的堆栈帧的当前状态的信息。
如果这个 Throwable 的栈轨迹不可写,调用这个方法是没有效果的。
http://docs.oracle.com/javase/7/docs/api/java/lang/Throwable.html
对于 Java 6:
由于 Java 6 没有Throwable(String message, Throwable cause, boolean enableSuppression,boolean writableStackTrace)
构造函数,我们可以使用以下技术抑制堆栈跟踪填充(借用 Scala,从Java 异常有多慢?)
class NoStackTraceRuntimeException extends RuntimeException {
@Override
public synchronized Throwable fillInStackTrace() {
return this;
}
}
用法相同:throw new NoStackTraceRuntimeException ()
,或者它的子类型。
我们也可以通过扩展来做同样的事情Throwable
:
class NoStackTraceThrowable extends Throwable {
@Override
public synchronized Throwable fillInStackTrace() {
return this;
}
}
但是,一个小问题是您不再可以catch
使用这些异常,Exception
因为这不是 的子类型Exception
,而是应该捕获NoStackTraceThrowable
或它的子类型。
更新:有关不同用例中性能的一些有趣统计数据,请查看这个SO question
对于 Java 7+,这里是一个异常示例,可以选择抑制堆栈跟踪。
public class SuppressableStacktraceException extends Exception {
private boolean suppressStacktrace = false;
public SuppressableStacktraceException(String message, boolean suppressStacktrace) {
super(message, null, suppressStacktrace, !suppressStacktrace);
this.suppressStacktrace = suppressStacktrace;
}
@Override
public String toString() {
if (suppressStacktrace) {
return getLocalizedMessage();
} else {
return super.toString();
}
}
}
这可以通过以下方式证明:
try {
throw new SuppressableStacktraceException("Not suppressed", false);
} catch (SuppressableStacktraceException e) {
e.printStackTrace();
}
try {
throw new SuppressableStacktraceException("Suppressed", true);
} catch (SuppressableStacktraceException e) {
e.printStackTrace();
}
这是基于Apache SystemML的 MLContextException的,其代码可在 GitHub 上的https://github.com/apache/systemml上找到。
抑制任何异常的堆栈跟踪的最简单方法是
throwable.setStackTrace(new StackTraceElement[0]);
如果异常有原因,您可能需要递归地执行相同的操作。
这也尽可能地减少了创建堆栈跟踪的成本
throwable 的堆栈跟踪在
Throwable#fillInStackTrace()
,由任何构造函数调用,因此无法避免。当实际使用 stacktrace 时,会延迟构造一个 StackTraceElement[]
Throwable#getOurStackTrace()
只有在尚未设置字段 Throwable.stackTrace 时才会发生这种情况。
将堆栈跟踪设置为任何非空值,避免在 Throwable#getOurStackTrace() 中构造 StackTraceElement[] 并尽可能减少性能损失。
正如 NG. 在回复中所暗示的那样,如果您一开始看到堆栈跟踪但随后由于相同的异常而消失,您很可能看到了 JVM 优化的效果。在这种情况下,以下问题非常相似。
没有 StackTrace 的 Java 中的 NullPointerException
您可以关闭此 JVM 功能,但我建议保持启用它并努力从一开始就防止错误,或者捕获它并更优雅地处理它。