1

What is the significance of the Finally block in a Try...[Catch]...Finally block?

Isn't this code

Resource r;
try{
  r = new Resource(); 
  r.methodThatThrowsException();
} catch (Exception e) {
  e.printStackTrace()
} finally {
  r.close()
}

equivalent to

Resource r;
try{
  r = new Resource(); 
  r.methodThatThrowsException();
} catch (Exception e) {
  e.printStackTrace()
}
r.close()

? I would understand if they have the same scope, but the fact that I have to define Resource r outside the try block anyway to use it in the finally block means that I see no advantage to using a finally block.

Am I missing something? Is there a certain case that I haven't thought of that requires a Finally block?

vikarjramun
  • 1,042
  • 12
  • 30

3 Answers3

4

In this case, they are equivalent since (a) the code catches any exception, including runtime exceptions that are thrown and (b) the catch block doesn't rethrow the exception, so the execution continues.

The finally block is generally used to ensure resource release in cases where either (a) or (b) don't hold. In newer Java implementations, wherever possible, you should use try-with-resources instead.

Piotr Wilkin
  • 3,446
  • 10
  • 18
  • Does this mean that even if my catch block rethrew the exception then the Finally block would run? Or what if my catch block did not catch IOException but only caught RuntimeException, and my code threw IOException? Then will my Finally block run? – vikarjramun Nov 14 '17 at 15:54
  • It is not exactly the same since one would need to catch `Throwable` to really catch everything (whether one should to such a thing is another question). @vikarjramun Finally beats everything (except `System.exit(42)`, obviously :P). Try this: `public int finallyBeatsEverything() { try { return 5; } finally { return 10; } }`. – Turing85 Nov 14 '17 at 16:02
  • @vikarjramun yes, exactly that would happen. – Piotr Wilkin Nov 14 '17 at 16:32
  • @Turing85 yes, technically you're right, but the only `Throwable`s that are not caught are `Error`s, which basically indicate something **very wrong** anyway and are by definition not recoverable. – Piotr Wilkin Nov 14 '17 at 16:34
1

No, it is not equivalent. In the first snippet r.close() will be always called, while in the second snippet r.close() might not be called:

  • when the try block throws an Error (what might happen when you use assertions and an assertion fails)
  • when the exception handler throws another Exception

To ensure the resources are always released close() method should be called from finally blocks.

Adam Siemion
  • 15,569
  • 7
  • 58
  • 92
1

The two code snippets are different: the second one will not close if exception handling block ends in another exception.

Here is an illustration:

public static void one() throws Exception {
    try {
        System.out.println("One");
        throw new Exception();
    } catch (Exception e) {
        System.out.println("Catch one");
        if (2 != 3) throw new Exception(); // "if" silences compiler's check
    } finally {
        System.out.println("Finally one");
    }
}
public static void two() throws Exception {
    try {
        System.out.println("Two");
        throw new Exception();
    } catch (Exception e) {
        System.out.println("Catch two");
        if (2 != 3) throw new Exception(); // "if" silences compiler's check
    }
    System.out.println("After two");
}

The call to one() prints Finally one, while After two never gets printed (demo 1).

The finally block becomes even more important when you catch specific exceptions (blindly catching Exception is nearly always a bad idea), because the try block may bypass your cleanup code by throwing an exception that you do not catch. Here is another illustration:

public static void error() throws Exception {
    try {
        System.out.println("Try");
        throw new Error();
    } catch (Exception e) {
        System.out.println("Catch");
        throw new Exception();
    } finally {
        System.out.println("Finally");
    }
}

This code prints Try and Finally, without Catch in the middle, because Error is not caught in the catch block (demo 2).

It goes without saying that human readers of your program will have easier time locating you clean-up code if you place it in the finally block.

Sergey Kalinichenko
  • 714,442
  • 84
  • 1,110
  • 1,523