2012-07-11 12 views
33

Jest to prawdopodobnie bardzo naiwne pytanie.Wyjątek bez śledzenia stosu w Javie

kiedyś uwierzyć, że w JavaThrowablezawsze zawiera ślad stosu. Czy to jest poprawne? Teraz wygląda na to, że łapię exceptionsbez śledzenia stosu. Czy jest sens? Czy jest możliwe możliwe wychwycić wyjątek bez śledzenia stosu?

+4

Co JVM? Środowisko? itp. Czy to pomaga? http://stackoverflow.com/questions/4659151/recurring-exception-without-a-stack-trace-how-torereset –

+0

@SB. Tak, to pomaga. Wielkie dzięki. Mam bardzo podobny problem: mam wiele wyjątków (NPE). Metoda 'error' z' log4j' loguje pewne wyjątki _ bez \ śledzenia stosu. – Michael

Odpowiedz

27

Jest możliwe, aby złapać Throwable obiekt w Javie bez śladu stosu:

Throwable(String message, Throwable cause, boolean enableSuppression,boolean writableStackTrace) 

konstruuje nowy Throwable z podano wiadomość szczegół, przyczyna, tłumienie włączona lub wyłączona, a do zapisu śladu stosu włączone lub wyłączone.

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

20

Dla Java 6:

Jako Java 6 nie posiada konstruktora Throwable(String message, Throwable cause, boolean enableSuppression,boolean writableStackTrace) możemy stłumić nadzienie StackTrace przy użyciu techniki (poniżej pożyczonej od Scala, poznał z How slow are Java exceptions?)

class NoStackTraceRuntimeException extends RuntimeException { 
    @Override 
    public synchronized Throwable fillInStackTrace() { 
     return this; 
    } 
} 

Użycie jest takie samo: throw new NoStackTraceRuntimeException() lub jego podtypy.

Możemy również zrobić to samo poprzez rozszerzenie Throwable:

class NoStackTraceThrowable extends Throwable { 
    @Override 
    public synchronized Throwable fillInStackTrace() { 
     return this; 
    } 
} 

Ale mały haczyk jest to, że już nie może catch nich wyjątek używając Exception jak to nie jest podtypem Exception zamiast powinna złapać NoStackTraceThrowable lub to są podtypy.

Aktualizacja: Dla ciekawych statystyk dotyczących wydajności w różnych usecases, sprawdź to SO question

+0

czy OP naprawdę wspomniał o java-6 w jego pytaniu !!! –

+4

@shekharsuman Nie, ale nie Java 7. Ta odpowiedź może pomóc komuś z Javą 6 :) – manikanta

+2

Nawet poza Javą 1.6, jest to nadal opłacalna metoda. Spowoduje to wytłumienie całego śledzenia stosu (jako że przekazana przyczyna 4 konstruktora parametrów zostanie wydrukowana). – DBK

6

Dla Java 7+, tutaj jest przykładem wyjątku gdzie ślad stosu może ewentualnie być tłumione.

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(); 
     } 
    } 
} 

ten można przedstawić:

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

ten oparty jest na MLContextException z Apache SystemML, kod, który jest dostępny na GitHub w https://github.com/apache/systemml.

0

Najprostszym sposobem, aby stłumić StackTrace na każdy wyjątek jest

throwable.setStackTrace(new StackTraceElement[0]); 

Jeśli wyjątek ma przyczynę, może trzeba zrobić to samo rekurencyjnie.

Zmniejsza to również kosztowne tworzenie śladu stos, jak to tylko możliwe

StackTrace na ratunkowym jest inicjowany w

Throwable#fillInStackTrace() 

, która jest wywoływana przez konstruktor, a zatem nie może być unikanym. Gdy StackTrace jest faktycznie stosowany An StackTraceElement [] leniwie jest skonstruowana

Throwable#getOurStackTrace() 

których tylko nastąpi, jeżeli Throwable.stackTrace pola nie była już ustawiona.

Ustawienie stosu stack na wartość inną niż null, unika konstrukcji StackTraceElement [] w Throwable # getOurStackTrace() i zmniejsza w jak największym stopniu obniżenie wydajności.

+1

Działa to, ale nie rozwiązuje problemu, który większość ludzi chce rozwiązać, eliminując ślady stosu. Generowanie śledzenia stosu jest powolne, a to może spowolnić kod, który często używa wyjątków do przesyłania wiadomości. Aby rozwiązać ten problem, należy uniemożliwić tworzenie śladów stosu, a nie usuwać ich, gdy zostały już utworzone. - To powiedziawszy, twoje podejście może nadal być przydatne do oszczędzania pamięci, gdy wiele wyjątków, nad którymi nie ma kontroli, jest przechowywanych z jakiegoś powodu. –

+0

Halo @Hans Adler, rozumiem twoją troskę, ale myślę, że moja odpowiedź redukuje kosztowne tworzenie śladu stosu, w miarę możliwości. Zobacz moją ostatnią edycję. –

Powiązane problemy