web-dev-qa-db-fra.com

Exception sans trace de pile dans Java

C'est probablement une question très naïve.

J'avais l'habitude de croire qu'un Throwable dans Javatoujours contient la trace de la pile. Est-ce correct? Maintenant, il semble que j'attrape exceptionssans la trace de la pile. Est-ce que ça fait du sens? Est-ce possible pour intercepter une exception sans la trace de pile?

44
Michael

Il est possible d'attraper un objet Throwable dans Java sans trace de pile:

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

Construit un nouveau fichier jetable avec le message de détail spécifié, la cause, la suppression activée ou désactivée et la trace de pile accessible en écriture activée ou désactivée.

http://docs.Oracle.com/javase/7/docs/api/Java/lang/Throwable.html

33
Alex W

Pour Java 6:

Comme Java 6 n'a pas le constructeur Throwable(String message, Throwable cause, boolean enableSuppression,boolean writableStackTrace), nous pouvons supprimer le remplissage de stacktrace en utilisant la technique ci-dessous (emprunté à Scala, appris depuis à quelle vitesse sont Java exceptions? )

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

L'utilisation est la même: throw new NoStackTraceRuntimeException (), ou ses sous-types.

Nous pouvons également faire de même en étendant Throwable:

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

Mais, un petit hic, c'est que vous ne pouvez plus catch ces exceptions en utilisant Exception car ce n'est pas un sous-type de Exception, vous devriez plutôt attraper NoStackTraceThrowable ou c'est sous-types.

Mise à jour : Pour des statistiques intéressantes sur les performances dans différents cas d'utilisation, vérifiez ceci SO question

25
manikanta

Pour Java 7+, voici un exemple d'une exception où la trace de pile peut éventuellement être supprimée.

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

Cela peut être démontré avec:

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

Ceci est basé sur l'exception MLContextException de Apache SystemML , dont le code est disponible sur GitHub à https://github.com/Apache/systemml .

9
Deron

La façon la plus simple de supprimer la trace de pile sur toute exception est

throwable.setStackTrace(new StackTraceElement[0]);

Si l'exception a une cause, vous devrez peut-être faire de même récursivement.

Cela réduit également autant que possible la création coûteuse de la trace de pile

La trace de pile pour un jetable est initialisée dans

Throwable#fillInStackTrace()

, qui est appelé par n'importe quel constructeur et ne peut donc pas être évité. Lorsque le stacktrace est réellement utilisé, un StackTraceElement [] est construit paresseusement dans

Throwable#getOurStackTrace()

ce qui ne se produit que si le champ Throwable.stackTrace n'était pas déjà défini.

La définition de stacktrace sur une valeur non nulle, évite la construction de StackTraceElement [] dans Throwable # getOurStackTrace () et réduit autant que possible la baisse des performances.