Just noticed today's Today's Finally WTF is relevant to JDBC in an important way. All *good* JDBC developers all ready know you should close your result sets, statements, and connections (in that order) in a finally block when you are done with them, but do you all know how they should be closed? In particular, while a finally block will be entered under most circumstances, there's no guarantee every line of code will be executed. Consider the following code I often come across:
Now, can you figure out what's wrong with this code? Imagine if the result set rs is never populated and stays null. The first line of the finally block will throw a NullPointerException, and the stmt.close() and con.close() will never be executed! Sure the code is guaranteed to enter the finally block, but if it fails on the first line, the rest of the code will be skipped. Next, compare this other common but still incorrect solution:
This solution is a little safer in that it avoids NullPointerExceptions, but its equally as useless as the first solution in that there are a number of reasons why the first line of code could still fail, for example if the result set is all ready closed. This solution actually worries me the most because clearly the developer went through the trouble of setting up the finally block and null pointer catches, but failed to fully understand how a finally block works. Now, I present a better solution:
Now is this solution safe? See that if rs or stmt fail to close, the call to con.close() will still be executed. Granted you could get fancy by adding logic to handle/log the exceptions or even catch Throwable (although catching Throwable's never a good practice), but that's a bit overkill. You could also nest your finally block with more finally blocks (just add finally block to the first line and put the rest inside it... and so on) although I tend to prefer this solution since its more readable.
Lastly, you could make helper methods for closing the the objects to make the code easier to work with such as:
Where the try/catch is inside the helper methods. Keep in mind this last solution isn't really different from the previous solution, just a code management improvement.