Java中没有堆栈跟踪的异常

Mic*_*ael 46 java exception stack-trace

这可能是一个非常天真的问题.

我曾经认为a Throwablein Java 总是包含堆栈跟踪.这是对的吗?现在看起来我exceptions 没有堆栈跟踪就抓住了.是否有意义?是否有可能在没有堆栈跟踪的情况下捕获异常?

Ale*_*x W 37

在没有堆栈跟踪的情况下,可以在Java中捕获Throwable对象:

Throwable(String message, Throwable cause, boolean enableSuppression,boolean writableStackTrace) 
Run Code Online (Sandbox Code Playgroud)

构造具有指定详细消息的新throwable,启用,禁用启用或禁用,以及启用或禁用可写堆栈跟踪.

http://docs.oracle.com/javase/7/docs/api/java/lang/Throwable.html

  • 它只是说启用或禁用“可写堆栈跟踪”。我不认为这意味着它不会捕获堆栈跟踪 (2认同)

man*_*nta 27

对于Java 6:

由于Java 6没有Throwable(String message, Throwable cause, boolean enableSuppression,boolean writableStackTrace)构造函数,我们可以使用以下技术来抑制stacktrace填充(从Scala借来,从Java异常有多慢了解)

class NoStackTraceRuntimeException extends RuntimeException {
    @Override
    public synchronized Throwable fillInStackTrace() {
        return this;
    }
}
Run Code Online (Sandbox Code Playgroud)

用法相同:throw new NoStackTraceRuntimeException (),或者它的子类型.

我们也可以通过扩展来做同样的事情Throwable:

class NoStackTraceThrowable extends Throwable {
    @Override
    public synchronized Throwable fillInStackTrace() {
        return this;
    }
}
Run Code Online (Sandbox Code Playgroud)

但是,一个小问题是你不再可以catch使用这些异常,Exception因为这不是子类型Exception,而是应该捕获NoStackTraceThrowable它或它的子类型.

更新:有关不同用例中性能的一些有趣统计数据,请查看此SO问题

  • @shekharsuman不,但不是Java 7.这个答案可能会帮助Java 6的人:) (5认同)
  • 即使在Java 1.6之外,这仍然是一种可行的方法.这将抑制整个堆栈跟踪(因为将打印出4参数构造函数的传入'原因'). (3认同)
  • 无需将仅返回“this”的方法标记为“同步”。 (3认同)
  • 如果你希望它被一个 `catch (Exception)` 块捕获,你的 `NoStackTraceThrowable` 可以改为扩展 `Exception`(并被称为 `NoStackTraceException`)。 (2认同)

Der*_*ron 10

对于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();
        }
    }
}
Run Code Online (Sandbox Code Playgroud)

这可以通过以下方式证明:

try {
    throw new SuppressableStacktraceException("Not suppressed", false);
} catch (SuppressableStacktraceException e) {
    e.printStackTrace();
}
try {
    throw new SuppressableStacktraceException("Suppressed", true);
} catch (SuppressableStacktraceException e) {
    e.printStackTrace();
}
Run Code Online (Sandbox Code Playgroud)

这是基于Apache SystemML的MLContextException,其代码可以在GitHub上的https://github.com/apache/systemml上找到.


Ste*_*com 5

在任何异常情况下抑制stacktrace的最简单方法是

throwable.setStackTrace(new StackTraceElement[0]);
Run Code Online (Sandbox Code Playgroud)

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

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

一个throwable的stacktrace初始化为

Throwable#fillInStackTrace()
Run Code Online (Sandbox Code Playgroud)

,任何构造函数都会调用它,因此无法避免。实际使用stacktrace时,会在以下位置延迟构造StackTraceElement []

Throwable#getOurStackTrace()
Run Code Online (Sandbox Code Playgroud)

如果尚未设置Throwable.stackTrace字段,则只会发生这种情况。

将stacktrace设置为任何非null值,可以避免在Throwable#getOurStackTrace()中构造StackTraceElement [],并尽可能降低性能损失。

  • 这行得通,但是并不能通过抑制堆栈跟踪来解决大多数人想要解决的问题。生成堆栈跟踪很慢,这会减慢大量使用异常进行消息传递的代码。为了解决这个问题,必须阻止创建堆栈跟踪,而不是在已创建堆栈跟踪时将其删除。-也就是说,当由于某种原因存储了许多无法控制的异常时,您的方法对于节省内存仍然有用。 (3认同)