Forgotten exceptions or “finally dengerous”

Hello everyone! Today I gonna show you how to loose the exception in Java.

In fact Java exception mechanism has been implemented with “nothing could be missed” in mind, but there is a gap that permits simply “forget” an exception.

Consider the following example:

class MyException extends Exception {}

class ExceptionTester {
	public static void run() throws MyException {
		try {
			// Some actions here
		} finally {
			throw new MyException();
		}
	}

	public static void main( String[] args ) {
		try {
			run();
		} catch ( MyException e ) {
			e.printStackTrace( System.out );
		}
	}
}

We have static run() method that declared to throw MyException. In this method there is try-finally construction: the only purpose is to call finally {} block in any case (whether exception occurs or not). For simplicity, the finally block just throws MyException.

Workflow of this example is quite obvious: run() method is performed, then (after empty try {}) flow control goes to finally {} clause where MyException is thrown. The exception is caught in main’s catch() and stack trace is sent to stdout. Here is the output of the program:

$ java ExceptionTester                                                         
MyException                                                                                                                              
        at ExceptionTester.run(ExceptionTester.java:8)                                                                                   
        at ExceptionTester.main(ExceptionTester.java:14)

Now let’s put next code under run()‘s try block:

int a = 10 / 0;

so our run method becomes:

public static void run() throws MyException {
	try {
		int a = 10 / 0;
	} finally {
		throw new MyException();
	}
}

Yes, you are quite right: this is a division by zero, and we are all absolutely sure that Java will generate a java.lang.ArithmeticException. But just try to run the program again, and you will see the same output:

$ java ExceptionTester                                                         
MyException                                                                                                                              
        at ExceptionTester.run(ExceptionTester.java:8)                                                                                   
        at ExceptionTester.main(ExceptionTester.java:14)

So, where is our ArithmeticException? It is obviously that operation it was generated by occurred before our throw new MyException();. The culprit here is finally clause: it just replaced the ArithmeticException with MyException, hence we know nothing about invalid arithmetic operation in run() method into main(). It could be a real problem in big and complex systems: you’ll spend much time, trying to find out what had happened that MyException has been thrown and even not imagine that there was a ArithmeticException somewhere before.

You may argue that this is a gap in the architecture of particular application: try-finally block was used without catch clause. Yes it was. But it does what I want: I want to execute some code (throw new MyException in our case) every time the flow control leaves the run() method. But I don’t want to catch any exceptions on that level: I just don’t know what to do with them, so I delegate this activity moving catch clause off the run().

Now bad news: this is really gap in all Java pre 7th versions (including current stable 1.6.x).
Good news: this gap has been fixed in Java 7.

try-with-resources statement has been added in Java 7 to deal with try-finally issues. It looks like:

try( /* Construct the object that grabs some resources */ ) {
  // Do smth.
}
// Resources are relinquished


Object that “grabs resources” should implement AutoCloseable interface. Java automatically frees the resources by calling close() method each time the object goes out of try scope. The try-with-resources has additional feature: all exceptions from close() method of resource-grabber object are suppressed by exception from the try statement. So, if we have two exceptions: one from within try block, and another one from close() method, the last one will be suppressed by (and, as you can see later, included into) close-method exception.

At first, let’s define new class that implements AutoCloseable interface:

class MemoryReleaseError extends Exception {}

class ResourceGrabber implements AutoCloseable {
    ResourceGrabber() {
        System.out.println( "Let's grab some memory..." );
    }

    public void close() throws MemoryReleaseError {
        throw new MemoryReleaseError();
    }
}

The class grabs some resources into constructor and releases them into close() method. If something goes wrong here (in our case – everything is going wrong:)) – MemoryReleaseError will be thrown.

Now we could rewrite run() method from our example using “buggy” try-finally clause (I’ve also renamed it to buggyRun):

static void buggyRun() throws MemoryReleaseError {
    ResourceGrabber grabber = new ResourceGrabber();
    try {
        int i = 10 / 0;
    } finally {
        grabber.close();
    }
}

Also don’t forget to change run() to buggyRun() into main() method:

class MemoryReleaseError extends Exception {}

class ResourceGrabber implements AutoCloseable {
    ResourceGrabber() {
        System.out.println( "Let's grab some memory..." );
    }

    public void close() throws MemoryReleaseError {
        throw new MemoryReleaseError();
    }
}

public class ExceptionTester {
    static void buggyRun() throws MemoryReleaseError {
        ResourceGrabber grabber = new ResourceGrabber();
        try {
            int i = 10 / 0;
        } finally {
            grabber.close();
        }
    }

    static void run() throws MemoryReleaseError {
        try( ResourceGrabber object = new ResourceGrabber() ) {
            int i = 10 / 0;
        }
    }

    public static void main( String[] args ) {
        try {
            buggyRun();
        } catch ( Exception e ) {
            e.printStackTrace( System.out );
        }
    }
}

Program’s output should be

Let's grab some memory...
MemoryReleaseError
	at ResourceGrabber.close(ExceptionTester.java:9)
	at ExceptionTester.buggyRun(ExceptionTester.java:19)
	at ExceptionTester.main(ExceptionTester.java:31)


The ResourceGrabber object is constructed in buggyRun(). It grabs some memory. Then java.lang.ArithmeticException is generated with devision by zero, flow control goes to finally block. close() method is called in order to release grabber resources but new exception (MemoryReleaseError) is thrown. As you may see from the output, our main’s try block has caught the only exception – MemoryReleaseError. We still known nothing about ArithmeticException.

Now, lets add “true” run() method, using Java 7th try-with-resources statement:

static void run() throws MemoryReleaseError {
    try( ResourceGrabber object = new ResourceGrabber() ) {
        int i = 10 / 0;
    }
}

Also, lets update our main() in the next way:

public static void main( String[] args ) {
    try {
        buggyRun();
    } catch ( Exception e ) {
        e.printStackTrace( System.out );
    }

    System.out.println( "\n-----------\n" );

    try {
        run();
    } catch ( Exception e ) {
        e.printStackTrace( System.out );

        if( e.getSuppressed().length > 0 ) {
            System.out.println( "Suppressed exception have been found:" );
            for( Throwable suppressed : e.getSuppressed() )
                System.out.format(
                    "Suppressed exception is '%s'\n",
                    suppressed.getClass().getName()
                );
        }
    }
}

Let’s compile and run the program and see what’s happened:

Let's grab some memory...
MemoryReleaseError
at ResourceGrabber.close(ExceptionTester.java:51)
at ExceptionTester.buggyRun(ExceptionTester.java:9)
at ExceptionTester.main(ExceptionTester.java:21)

-----------

Let's grab some memory...
java.lang.ArithmeticException: / by zero
at ExceptionTester.run(ExceptionTester.java:15)
at ExceptionTester.main(ExceptionTester.java:29)
Suppressed: MemoryReleaseError
at ResourceGrabber.close(ExceptionTester.java:51)
at ExceptionTester.run(ExceptionTester.java:16)
... 1 more
Suppressed exception have been found:
Suppressed exception is 'MemoryReleaseError'

The pre-“——” part remains the same: we have performed buggyRun() and stayed in the lack of java.lang.ArithmeticException exception.

Get down to discuss run() call: method run() is performed. The ResourceGrabber object is constructed in try-with-resources statement. Then ArithmeticException is generated, and grabber’s close() method is implicitly called, which generates MemoryReleaseError exception. Flow control goes to the main() and finds itself under catch( Exception e ) statement. ‘e’ is the very first exception occurred: java.lang.ArithmeticException one. The try-with-resources has suppressed our MemoryReleaseError exception and put it into ArithmeticException!

Class Throwable got getSuppressed() method, that returns array (Throwable[]) of all suppressed exceptions so we could easy get access to each of them and miss nothing important.

The C++ doesn’t have such problems: it guarantees that terminate() will be called if any new exception is thrown while existing exception hasn’t yet reached the try-catch block. There is no finally block in C++ hence the only possibility to reproduce the situation mentioned above is to raise exception in the destructor. In most cases this is a bad idea and you should do this very carefully (as almost everything you do into destructors :)):

#include <iostream>


class VeryImportantException {};
class MyException {};

struct ExceptionTester {
	void run() {
		std::cout << "ExceptionTester::run()" << std::endl;

		std::cout << "Before throwing VeryImportantException" << std::endl;
		throw VeryImportantException();
		std::cout << "After VeryImportantException has been thrown" << std::endl;
	}

	~ExceptionTester() {
		std::cout << "~ExceptionTester" << std::endl;

		std::cout << "Before throwing MyException" << std::endl;
		throw MyException();
		std::cout << "After MyException has been thrown" << std::endl;
	}
};


int main() {
	try {
		ExceptionTester e;
		e.run();
	} catch( const MyException& e ) {
		std::cout << "MyException has been cought!" << std::endl;
	} catch( const VeryImportantException& e ) {
		std::cout << "VeryImportantException has been cought!" << std::endl;
	}

	return 0;
}

Two methods have been defined for the class ExceptionTester: run() which throws VeryImportantException and destructor which throws MyException. In main we just construct the ExceptionTester object on stack in try-catch block. If you compile and run the program above, you should get:

ExceptionTester::run()
Before throwing VeryImportantException
~ExceptionTester
Before throwing MyException
terminate called after throwing an instance of 'MyException'
Aborted

We enter the ExceptionTester::run(), then we throw VeryImportantException, then flow control goes out of scope where ExceptionTester object was defined hence ~ExceptionTester was called and just after throwing MyException we’ve got ‘terminate called after throwing an instance of ‘MyException’ and termination. That’s happened because MyException has been thrown while VeryImportantException hasn’t reached the try-catch block yet. Even with this behavior we know nothing about VeryImportantException (which was the first problem), but C++ doesn’t give us an ability just to “forget” about it and continue with program execution.

C++ behavior is the strictest one among Java and C#, and obviously isn’t a panacea: it’s nice that C++ doesn’t give us ability to lose some exception but terminate() in situation where we really may fix the problem in runtime – is not a good idea. Java 7th with its suppressed exceptions and try-with-resources statement gives us the more flexible way for solving issues mentioned above, and as a result – more benefits during design stage.

Leave a comment