59

这可能是一个非常幼稚的问题。

我曾经相信ThrowableJava中的 a总是包含堆栈跟踪。这是正确的吗?

现在看起来我在没有堆栈跟踪的情况下捕获了异常。是否有意义?是否可以在没有堆栈跟踪的情况下捕获异常?

4

5 回答 5

36

可以在没有堆栈跟踪的情况下在 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

于 2012-07-11T14:07:42.857 回答
32

对于 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

于 2014-08-15T09:54:40.513 回答
14

对于 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上找到。

于 2016-09-22T22:35:20.513 回答
7

抑制任何异常的堆栈跟踪的最简单方法是

throwable.setStackTrace(new StackTraceElement[0]);

如果异常有原因,您可能需要递归地执行相同的操作。

这也尽可能地减少了创建堆栈跟踪的成本

throwable 的堆栈跟踪在

Throwable#fillInStackTrace()

,由任何构造函数调用,因此无法避免。当实际使用 stacktrace 时,会延迟构造一个 StackTraceElement[]

Throwable#getOurStackTrace()

只有在尚未设置字段 Throwable.stackTrace 时才会发生这种情况。

将堆栈跟踪设置为任何非空值,避免在 Throwable#getOurStackTrace() 中构造 StackTraceElement[] 并尽可能减少性能损失。

于 2016-10-14T13:50:46.087 回答
2

正如 NG. 在回复中所暗示的那样,如果您一开始看到堆栈跟踪但随后由于相同的异常而消失,您很可能看到了 JVM 优化的效果。在这种情况下,以下问题非常相似。

没有堆栈跟踪的重复异常 - 如何重置?

没有 StackTrace 的 Java 中的 NullPointerException

您可以关闭此 JVM 功能,但我建议保持启用它并努力从一开始就防止错误,或者捕获它并更优雅地处理它。

于 2020-03-06T07:22:36.933 回答