This example covers some advanced features and use-cases for Exceptions.

Examining the callstack programmatically

The primary use of exception stacktraces is to provide information about an application error and its context so that the programmer can diagnose and fix the problem. Sometimes it can be used for other things. For example, a SecurityManager class may need to examine the call stack to decide whether the code that is making a call should be trusted.

You can use exceptions to examine the call stack programatically as follows:

Exception ex = new Exception();   // this captures the call stack
StackTraceElement[] frames = ex.getStackTrace();
System.out.println("This method is " + frames[0].getMethodName());
System.out.println("Called from method " + frames[1].getMethodName());

There are some important caveats on this:

  1. The information available in a StackTraceElement is limited. There is no more information available than is displayed by printStackTrace. (The values of the local variables in the frame are not available.)
  2. The javadocs for getStackTrace() state that a JVM is permitted to leave out frames:

Some virtual machines may, under some circumstances, omit one or more stack frames from the stack trace. In the extreme case, a virtual machine that has no stack trace information concerning this throwable is permitted to return a zero-length array from this method.

Optimizing exception construction

As mentioned elsewhere, constructing an exception is rather expensive because it entails capturing and recording information about all stack frames on the current thread. Sometimes, we know that that information is never going to be used for a given exception; e.g. the stacktrace will never be printed. In that case, there is an implementation trick that we can use in a custom exception to cause the information to not be captured.

The stack frame information needed for stacktraces, is captured when the Throwable constructors call the Throwable.fillInStackTrace() method. This method is public, which means that a subclass can override it. The trick is to override the method inherited from Throwable with one that does nothing; e.g.

public class MyException extends Exception {
    // constructors

    @Override 
    public void fillInStackTrace() {
        // do nothing
    }
}

The problem with this approach is that an exception that overrides fillInStackTrace() can never capture the stacktrace, and is useless in scenarios where you need one.

Erasing or replacing the stacktrace

In some situations, the stacktrace for an exception created in the normal way contains either incorrect information, or information that the developer does not want to reveal to the user. For these scenarios, the Throwable.setStackTrace can be used to replace the array of StackTraceElement objects that holds the information.

For example, the following can be used to discard an exception’s stack information:

exception.setStackTrace(new StackTraceElement[0]);

Suppressed exceptions

Java 7 introduced the try-with-resources construct, and the associated concept of exception suppression. Consider the following snippet: