Exception without stack trace in Java

56,322

Solution 1

It's possible to catch a Throwable object in Java without a stack trace:

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

Constructs a new throwable with the specified detail message, cause, suppression enabled or disabled, and writable stack trace enabled or disabled.

public Throwable fillInStackTrace()

Fills in the execution stack trace. This method records within this Throwable object information about the current state of the stack frames for the current thread.

If the stack trace of this Throwable is not writable, calling this method has no effect.

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

Solution 2

For Java 6:

As Java 6 doesn't have the Throwable(String message, Throwable cause, boolean enableSuppression,boolean writableStackTrace) constructor, we can suppress the stacktrace filling using below technique (borrowed from Scala, came to know from How slow are Java exceptions?)

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

Usage is same: throw new NoStackTraceRuntimeException (), or it's subtypes.

We can also do the same by extending Throwable:

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

But, a small catch is that you no longer can catch these exception using Exception as this is not subtype of Exception, instead should catch NoStackTraceThrowable or it's subtypes.

Update: For some interesting stats on performance in different usecases, check this SO question

Solution 3

For Java 7+, here is an example of an exception where the stack trace can optionally be suppressed.

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

This can be demonstrated with:

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

This is based on the MLContextException from Apache SystemML, the code of which is available on GitHub at https://github.com/apache/systemml.

Solution 4

The easiest way to suppress the stacktrace on any Exception is

throwable.setStackTrace(new StackTraceElement[0]);

If the exception has a cause, you may need to do the same recursively.

This also reduces the costly creation of the stack trace, as much as possible

The stacktrace for a throwable is initialized in

Throwable#fillInStackTrace()

, which is called by any constructor and thus cannot be avoided. When the stacktrace actually is used, an StackTraceElement[] is lazily constructed in

Throwable#getOurStackTrace()

which only happens, if the field Throwable.stackTrace was not already set.

Setting the stacktrace to whatever non null value, avoids the construction of the StackTraceElement[] in Throwable#getOurStackTrace() and reduces the performance penalty as much as possible.

Solution 5

As hinted at in the reply by NG., if you are seeing the stacktrace at first but then it disappears for the same exception, you are most likely seeing the effects of JVM optimization. In that case, the following questions are very similar.

Recurring Exception without a stack trace - how to reset?

NullPointerException in Java with no StackTrace

You can turn this JVM feature off, but I would recommend keeping it enabled and working towards preventing the error in the first place, or catching it and handling it more gracefully.

Share:
56,322
Michael
Author by

Michael

Scala (moslty) programmer

Updated on May 16, 2020

Comments

  • Michael
    Michael almost 4 years

    This is probably a very naive question.

    I used to believe that a Throwable in Java always contains the stack trace. Is it correct?

    Now it looks like that I catch exceptions without the stack trace. Does it make sense? Is it possible to catch an exception without the stack trace?