2012-07-11 15 views
33

Questa è probabilmente una domanda molto ingenua.Eccezione senza stack trace in Java

Ero solito credere che uno Throwable in Javasempre contenga la traccia dello stack. È corretto? Ora sembra che prenda exceptionssenza la traccia dello stack. Ha senso? È possibile rilevare un'eccezione senza la traccia dello stack?

+4

Cosa JVM? Ambiente? ecc. Questo aiuta? http://stackoverflow.com/questions/4659151/recurring-exception-without-a-stack-trace-how-to-reset –

+0

@SB. Sì, questo aiuta. Molte grazie. Ho un problema molto simile: ho un sacco di eccezioni (NPE). Il metodo 'error' di' log4j' registra alcune eccezioni _ senza traccia dello stack. – Michael

risposta

27

E 'possibile prendere un oggetto Throwable in Java senza lasciare traccia di stack:

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

Costruisce una nuova Throwable con la scrivibile stack trace specificato messaggio di dettaglio, la causa, la soppressione abilitata o disabilitata, e abilitato o disabilitato.

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

20

Per Java 6:

Come Java 6 non ha il costruttore Throwable(String message, Throwable cause, boolean enableSuppression,boolean writableStackTrace), siamo in grado di sopprimere il ripieno stacktrace usando sotto la tecnica (presa in prestito da Scala, è venuto a sapere da How slow are Java exceptions?)

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

uso è lo stesso: throw new NoStackTraceRuntimeException(), o è sottotipi.

possiamo anche fare lo stesso, estendendo Throwable:

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

Ma, un piccolo problema è che non è più possibile catch questi eccezione utilizzando Exception come questo non è sottotipo di Exception, invece dovrebbe prendere NoStackTraceThrowable o sono sottotipi.

Aggiornamento: Per alcune interessanti statistiche sulle prestazioni in diversi casi d'uso, controllare questo SO question

+0

OP ha davvero menzionato java-6 nella sua domanda !!! –

+4

@shekharsuman No, ma nessuna Java 7. Questa risposta potrebbe aiutare qualcuno con Java 6 :) – manikanta

+2

Anche al di fuori di Java 1.6, questo è ancora un metodo valido. Questo sopprimerà l'intera traccia dello stack (come il passato in "causa" del costruttore del parametro 4 verrà stampato). – DBK

6

Per Java 7+, ecco un esempio di un'eccezione in cui la traccia dello stack può opzionalmente essere soppresso.

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

Questo può essere dimostrato con:

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

Questo si basa sulla MLContextException dal Apache SystemML, il cui codice è disponibile su GitHub a https://github.com/apache/systemml.

0

Il modo più semplice per sopprimere lo stacktrace su qualsiasi eccezione è

throwable.setStackTrace(new StackTraceElement[0]); 

Se l'eccezione ha una causa, potrebbe essere necessario fare la stessa cosa in modo ricorsivo.

riduce Questa anche la creazione costosa della stack, per quanto possibile

Lo stacktrace di throwable viene inizializzato in

Throwable#fillInStackTrace() 

, che è chiamato da qualsiasi costruttore e pertanto non può essere evitato. Quando viene utilizzato lo stacktrace realtà, uno StackTraceElement [] è pigramente costruito in

Throwable#getOurStackTrace() 

che avviene solo se il Throwable.stackTrace campo non è già stato impostato.

L'impostazione dello stacktrace su qualsiasi valore non nullo, evita la costruzione dello StackTraceElement [] in Throwable # getOurStackTrace() e riduce il più possibile la penalizzazione delle prestazioni.

+1

Funziona, ma non risolve il problema che molte persone vogliono risolvere eliminando le tracce dello stack. La generazione di una traccia dello stack è lenta e questo può rallentare il codice che utilizza molto le eccezioni per la messaggistica. Per risolvere questo problema, è necessario impedire la creazione delle tracce dello stack, non eliminarle quando sono già state create. - Detto questo, il tuo approccio potrebbe essere ancora utile per risparmiare memoria quando vengono memorizzate molte eccezioni su cui non si ha controllo per qualche motivo. –

+0

Halo @Hans Adler, comprendo la tua preoccupazione, ma penso che la mia risposta riduca il più possibile la costosa creazione della traccia dello stack. Per favore, vedi la mia ultima modifica. –

Problemi correlati