這可能是一個非常天真的問題。Java中沒有堆棧跟蹤的異常
我曾經相信一個Throwable
在Java
總是包含堆棧跟蹤。這是對的嗎? 現在看起來像我抓exceptions
沒有堆棧跟蹤。是否有意義?是否可能在沒有堆棧跟蹤的情況下捕獲異常?
這可能是一個非常天真的問題。Java中沒有堆棧跟蹤的異常
我曾經相信一個Throwable
在Java
總是包含堆棧跟蹤。這是對的嗎? 現在看起來像我抓exceptions
沒有堆棧跟蹤。是否有意義?是否可能在沒有堆棧跟蹤的情況下捕獲異常?
這有可能趕在Java中Throwable對象沒有一個堆棧跟蹤:
Throwable(String message, Throwable cause, boolean enableSuppression,boolean writableStackTrace)
構造一個新的Throwable與 指定詳細消息,cause,啓用或禁用抑制, 可寫的堆棧跟蹤啓用或禁用。
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)
構造,就可以抑制使用以下技術堆棧跟蹤填充(從斯卡拉借來的,來自How slow are Java exceptions?就知道了)
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
或它是亞型。
更新:有關在不同usecases性能的一些有趣的統計數據,檢查該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();
}
這是基於從MLContextException Apache SystemML,代碼,其中爲https://github.com/apache/systemml可用GitHub上。
以抑制任何異常堆棧跟蹤的最簡單方法是
throwable.setStackTrace(new StackTraceElement[0]);
如果該異常有一個原因,你可能需要遞歸這樣做。
這也降低了昂貴的創建堆棧跟蹤的,儘可能
用於拋出該異常堆棧在
Throwable#fillInStackTrace()
初始化,這是由任何構造稱爲並且因此不能應避免。 當實際棧跟蹤被使用的,一個StackTraceElement []被懶惰地在
Throwable#getOurStackTrace()
其中只發生,如果字段Throwable.stackTrace還沒有設置構成。
將stacktrace設置爲任何非null值,避免在Throwable#getOurStackTrace()中構造StackTraceElement [],並儘可能降低性能損失。
這是有效的,但它並不能解決大多數人想要通過抑制堆棧跟蹤來解決的問題。生成堆棧跟蹤速度很慢,這可能會減慢大量使用異常消息的代碼。要解決這個問題,必須防止創建堆棧跟蹤,而不是在它們已經創建時刪除它們。 - 也就是說,當出於某種原因存儲了很多無法控制的異常時,您的方法仍然可以用於節省內存。 – 2016-11-04 19:57:00
Halo @Hans Adler,我理解你的擔憂,但我認爲我的答案也儘可能地減少了堆棧跟蹤的代價高昂的創建。請參閱我的上次編輯。 – 2016-11-06 10:27:57
什麼是JVM?環境?等等有幫助嗎? http://stackoverflow.com/questions/4659151/recurring-exception-without-a-stack-trace-how-to-reset – 2012-07-11 14:07:06
@SB。是的,這確實有幫助。非常感謝。我有一個非常類似的問題:我有很多例外(NPE)。 'log4j'的方法''錯誤'記錄了一些異常_而沒有堆棧跟蹤。 – Michael 2012-07-11 14:25:12