2012-07-11 21 views
33

Esta es probablemente una pregunta muy ingenua.Excepción sin seguimiento de pila en Java

Solía ​​creer que un Throwable en Java siempre contiene el seguimiento de la pila. ¿Es correcto? Ahora parece que atrapo exceptionssin el seguimiento de la pila. ¿Tiene sentido? ¿Es posible para capturar una excepción sin el seguimiento de pila?

+4

¿Qué JVM? ¿Ambiente? etc. ¿Ayuda esto? http://stackoverflow.com/questions/4659151/recurring-exception-without-a-stack-trace-how-to-reset –

+0

@SB. Sí, esto ayuda. Muchas gracias. Tengo un problema muy similar: tengo muchas excepciones (NPE). El método 'error' de' log4j' registra algunas excepciones _with_ el seguimiento de la pila. – Michael

Respuesta

27

Es posible coger un objeto Throwable en Java sin un seguimiento de pila:

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

construye un nuevo throwable con el seguimiento de la pila grabable especificado mensaje de detalle, la causa, la supresión activado o desactivado, y habilitado o deshabilitado

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

20

Para Java 6:

Como Java 6 no tiene el constructor Throwable(String message, Throwable cause, boolean enableSuppression,boolean writableStackTrace), podemos suprimir el llenado StackTrace mediante el siguiente técnica (tomado de Scala, llegó a conocer a partir How slow are Java exceptions?)

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

uso es igual: throw new NoStackTraceRuntimeException(), o es subtipos.

También podemos hacer lo mismo mediante la extensión de Throwable:

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

embargo, un pequeño problema es que ya no se puede catch estos excepción usando Exception ya que esto no es subtipo de Exception, en vez debe coger NoStackTraceThrowable o son subtipos.

actualización: Para algunas estadísticas interesantes sobre el rendimiento en diferentes casos de uso, mira esto SO question

+0

OP realmente mencionó java-6 en su pregunta !!! –

+4

@shekharsuman No, pero tampoco Java 7. Esta respuesta podría ayudar a alguien con Java 6 :) – manikanta

+2

Incluso fuera de Java 1.6, este sigue siendo un método viable. Esto suprimirá toda la traza de pila (ya que se pasará la 'causa' pasada en el constructor de 4 parámetros). – DBK

6

Para Java 7+, aquí es un ejemplo de una excepción en el que el seguimiento de la pila opcionalmente se puede suprimir.

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

Esto se puede demostrar con:

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

Esto se basa en la MLContextException de Apache SystemML, el código de los cuales está disponible en GitHub en https://github.com/apache/systemml.

0

La forma más fácil de suprimir el StackTrace sobre cualquier excepción es

throwable.setStackTrace(new StackTraceElement[0]); 

Si la excepción tiene una causa, puede que tenga que hacer lo mismo de forma recursiva.

reduce Esto también la creación costoso de la traza de la pila, tanto como sea posible

El StackTrace para un throwable se inicializa en

Throwable#fillInStackTrace() 

, que se llama por cualquier constructor y por lo tanto no puede ser evitado Cuando se utiliza el StackTrace en realidad, un StackTraceElement [] se construye con pereza en

Throwable#getOurStackTrace() 

que sólo ocurre, si el Throwable.stackTrace campo no fue ya establecido.

Configurando stacktrace a cualquier valor no nulo, evita la construcción de StackTraceElement [] en Throwable # getOurStackTrace() y reduce la penalización de rendimiento tanto como sea posible.

+1

Esto funciona, pero no resuelve el problema que la mayoría de las personas quiere resolver mediante la supresión de los rastros de pila. Generar un seguimiento de pila es lento, y esto puede ralentizar el código que usa muchas excepciones para enviar mensajes. Para abordar esto, uno debe evitar la creación de los rastros de pila, no eliminarlos cuando ya se han creado. - Dicho esto, su enfoque aún podría ser útil para ahorrar memoria cuando, por alguna razón, se almacenan muchas excepciones sobre las cuales uno no tiene control. –

+0

Halo @ Hans Adler, entiendo su preocupación, pero creo que mi respuesta también reduce la costosa creación del seguimiento de la pila, tanto como sea posible. Consulte mi última edición. –

Cuestiones relacionadas