Playing with Try, Catch and Finally

I read a blog post (Greek) recently that described the path Java takes when executing a try, catch, finally block. But before I continue I would like you to consider the following code. What will be printed out?

public class ErrorClass {
    public static void main(String[] args) {
        System.out.println(getMessage());
    }

    private static String getMessage() {
        String toReturn = "Initializing";
        try {
            throwException();
            toReturn += "+No Exception";

            return toReturn;
        } catch (Exception e) {
            toReturn += "+Catch";

            return toReturn +" from Catch";
        } finally {
            toReturn += "+Finally";

            return toReturn +" from Finally";
        }
    }

    private static String throwException() throws Exception {
        throw new Exception("original exception");
    }
}

a) "Initializing+No Exception" b) "Initializing+Catch from Catch" c) "Initializing+Catch+Finally from Catch" d) "Initializing+Catch+Finally from Finally"

The correct answer is d. Let's see why.

The finally clause in general is a way to ensure that certain actions are taken after a specific block of code. A significant example would be the release of resources as described in Resource Acquisition is Initialization (RAII) design pattern. That is why whatever is inside a finally block, it will be executed.

Things get a little complicated when return statements are involved and this is what we are going to talk about. Let's see a simple example.

NOTE: This is just an example. This is by no means a real production code.

public String readString(String fileName) {
    String oneLine = null;
    BufferedReader fileIn = null;
    try {
        FileReader theFile = new FileReader( "file.txt" );
        fileIn  = new BufferedReader( theFile );
        oneLine = fileIn.readLine();
        return oneLine;
    } catch (Exception e) {
        // Oversimplified catch clause
        return oneLine;
    } finally {
        try {
            fileIn.close();
        } catch (IOException e) {
            // Do something
        }
    } 
}

In the code listing, the execution will follow the path (assuming no exception is thrown): all the way to the first return statement (the one inside the try block), then the finally clause and then it will return the oneLine. If there was an exception thrown, it will stop in the second return statement (the one inside the catch block), execute the finally block and then return the oneLine.

Let's change the above code to include a return statement inside the finally block:

public String readString(String fileName) {
        String oneLine = null;
        BufferedReader fileIn = null;
        try {
            FileReader theFile = new FileReader( fileName );
            fileIn = new BufferedReader( theFile );
            oneLine = fileIn.readLine();
        } catch (Exception e) {
            // Oversimplified catch clause
        } finally {
            try {
                fileIn.close();
            } catch (IOException e) {
                // Do something
            }
            return oneLine;
        }
}

Since the return statement inside the finally block will be executed, it only makes sense to add it there instead of duplicating it in both the try and the catch. But consider the following block of code:

public class HiddenException {
    public static void main(String[] args) {
        try {
            System.out.println(throwException());
        } catch (Exception e) {
            System.out.println("Caught it.");
        }
    }

    public static String throwException() throws Exception {
        try {
            throw new Exception();
        } finally {
            return "Bypass throw statement";
        }
    }
}

based on James Stauffer's Blog post "Don't return in a finally clause"

This code takes advantage the fact that the return inside the finally will be executed and successfully bypasses the throw statement. This happens because before executing the throw statement, it will first execute the finally clause, and since there is a return in there, it will be executed.

According to the Java Language Specification:

If there are any enclosing try statements whose try blocks contain the throw statement, then any finally clauses of those try statements are executed as control is transferred outward, until the thrown value is caught. Note that abrupt completion of a finally clause can disrupt the transfer of control initiated by a throw statement.

Returning inside a finally block is one way of achiving Abrupt completion of a finally clause. The Java Compiler even warns you that "finally block does not complete normally". So avoid having a return statement inside a finally at all costs. It is really dangerous and a bad practice in general. If you're using Eclipse, I suggest you set this exception as "Error" instead of "Warning".

The best strategy to follow is simply what Stauffer advices, never use a return statement inside a finally clause.