In try/finally, does it matter what's inside the try?
-
20-12-2019 - |
Question
Is there any functional difference?
Connection c = null;
try {
c = getConnection();
c.doStuff();
} finally {
if (c!=null) c.close();
}
vs
Connection c = null;
c = getConnection();
c.doStuff();
try {
} finally {
if (c!=null) c.close();
}
vs
Connection c = null;
try {
c = getConnection();
} finally {
if (c!=null) c.close();
}
c.doStuff();
I feel that all of them will do the same thing in all cases
Solution
An exception that occurs outside of a try-finally
block is by definition an unhandled exception. That being the case, you don't have any guarantees about how the operating system or runtime will deal with it. Chances are good that an exception unwind won't be triggered, your code will simply abort (maybe abend describes it better in this discussion--"abnormal end"), and your finally
block will never execute.
The point of try-finally
is to guarantee that code cleanup occurs, and occurs in the correct context.
You must be thinking that the code in the finally
block is always going to execute no matter what, and that it is going to execute after the entire method finishes, therefore it doesn't matter whether the other code is located inside or outside the try-finally
construct, but that is not correct.
So if you want any run-time guarantees of correct behavior your first example is the only correct one.
In your first example, you acquire and more importantly use a connection (to a database, one would presume) inside the
try
block. If an exception occurs within thetry
block, then thefinally
block will execute and close your connection.In your second example, your connection is acquired and used completely outside of the
try-catch
construct. If an exception occurs using the connection, it is likely that the whole context will just be tossed out, yourfinally
block will not execute, and your connection will not be closed.In your third example,
finally
is going to execute aftertry
, but before any code that comes after thefinally
block. You will generate an exception trying to use the connection, because the connection has already been explicitly closed.
OTHER TIPS
Craig already addressed the unhandled exception issue, but I wanted to make it clear. I coded up two examples (the last is just bad because you could be working with a broken connection after an exception has occurred, don't do that). Here is a simple example that throws an ArrayIndexOutOfBoundsException:
class TryCatchFinally {
static int [] array = new int[1];
public static void main(String [] args) throws Exception {
if (args[0].startsWith("1")) {
version1();
} else if (args[0].startsWith("2")) {
version2();
}
}
static int version1() {
int r = 0;
try {
System.out.println("In Try.");
return array[1];
} catch (Exception e) {
System.out.println("In Catch.");
} finally {
System.out.println("In Finally.");
}
System.out.println("In Return.");
return r;
}
static int version2() {
int r = array[1];
try {
System.out.println("In Try.");
} catch (Exception e) {
System.out.println("In Catch.");
} finally {
System.out.println("In Finally.");
}
System.out.println("In Return.");
return r;
}
}
And here is the execution:
(TryCatchFinally)$ javac *.java
(TryCatchFinally)$ java TryCatchFinally 1
In Try.
In Catch.
In Finally.
In Return.
(TryCatchFinally)$ java TryCatchFinally 2
Exception in thread "main" java.lang.ArrayIndexOutOfBoundsException: 1
at TryCatchFinally.version2(TryCatchFinally.java:24)
at TryCatchFinally.main(TryCatchFinally.java:7)
(TryCatchFinally)$
As you can see in the first version an exception handler was registered because the exception occurred within the context of a try block. In the second version there was no registered exception handler and the default exception handler was invoked (meaning an uncaught exception).