2012-07-11 41 views
33

這可能是一個非常天真的問題。Java中沒有堆棧跟蹤的異常

我曾經相信一個ThrowableJava總是包含堆棧跟蹤。這是對的嗎? 現在看起來像我抓exceptions沒有堆棧跟蹤。是否有意義?是否可能在沒有堆棧跟蹤的情況下捕獲異常?

+4

什麼是JVM?環境?等等有幫助嗎? http://stackoverflow.com/questions/4659151/recurring-exception-without-a-stack-trace-how-to-reset – 2012-07-11 14:07:06

+0

@SB。是的,這確實有幫助。非常感謝。我有一個非常類似的問題:我有很多例外(NPE)。 'log4j'的方法''錯誤'記錄了一些異常_而沒有堆棧跟蹤。 – Michael 2012-07-11 14:25:12

回答

27

這有可能趕在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

20

對於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

+0

確實OP在他的問題中真的提到了java-6! – 2014-08-15 09:56:27

+4

@shekharsuman不,但都不是Java 7.這個答案可能有助於Java 6的人:) – manikanta 2014-08-15 10:09:43

+2

即使在Java 1.6之外,這仍然是一個可行的方法。這將抑制整個堆棧跟蹤(因爲4參數構造函數的「原因」將被打印出來)。 – DBK 2015-05-08 13:17:43

6

對於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上。

0

以抑制任何異常堆棧跟蹤的最簡單方法是

throwable.setStackTrace(new StackTraceElement[0]); 

如果該異常有一個原因,你可能需要遞歸這樣做。

這也降低了昂貴的創建堆棧跟蹤的,儘可能

用於拋出該異常堆棧在

Throwable#fillInStackTrace() 

初始化,這是由任何構造稱爲並且因此不能應避免。 當實際棧跟蹤被使用的,一個StackTraceElement []被懶惰地在

Throwable#getOurStackTrace() 

其中只發生,如果字段Throwable.stackTrace還沒有設置構成。

將stacktrace設置爲任何非null值,避免在Throwable#getOurStackTrace()中構造StackTraceElement [],並儘可能降低性能損失。

+1

這是有效的,但它並不能解決大多數人想要通過抑制堆棧跟蹤來解決的問題。生成堆棧跟蹤速度很慢,這可能會減慢大量使用異常消息的代碼。要解決這個問題,必須防止創建堆棧跟蹤,而不是在它們已經創建時刪除它們。 - 也就是說,當出於某種原因存儲了很多無法控制的異常時,您的方法仍然可以用於節省內存。 – 2016-11-04 19:57:00

+0

Halo @Hans Adler,我理解你的擔憂,但我認爲我的答案也儘可能地減少了堆棧跟蹤的代價高昂的創建。請參閱我的上次編輯。 – 2016-11-06 10:27:57