One of the things that always bugs me about using Readers and Streams in Java is that the close()
method can throw an exception. Since it's a good idea to put the close method in a finally block, that necessitates a bit of an awkward situation. I usually use this construction:
FileReader fr = new FileReader("SomeFile.txt"); try { try { fr.read(); } finally { fr.close(); } } catch(Exception e) { // Do exception handling }
But I've also seen this construction:
FileReader fr = new FileReader("SomeFile.txt"); try { fr.read() } catch (Exception e) { // Do exception handling } finally { try { fr.close(); } catch (Exception e) { // Do exception handling } }
I prefer the first construction because there's only one catch block and it just seems more elegant. Is there a reason to actually prefer the second or an alternate construction?
UPDATE: Would it make a difference if I pointed out that both read
and close
only throw IOExceptions? So it seems likely to me that, if read fails, close will fail for the same reason.
Nesting try-catch blocks severely impacts the readability of source code because it makes it to difficult to understand which block will catch which exception.
Yes, we can declare a try-catch block within another try-catch block, this is called nested try-catch block.
Exponentially because if each method branches in two different ways then every time you call another method you're squaring the previous number of potential outcomes. By the time you've called five methods you are up to 256 possible outcomes at a minimum.
Yes, we can define one try block with multiple catch blocks in Java. Every try should and must be associated with at least one catch block.
I'm afraid there's a big problem with the first example, which is that if an exception happens on or after the read, the finally
block executes. So far so good. But what if the fr.close()
then causes another exception to be thrown? This will "trump" the first exception (a bit like putting return
in a finally
block) and you will lose all information about what actually caused the problem to begin with.
Your finally block should use:
IOUtil.closeSilently(fr);
where this utility method just does:
public static void closeSilently(Closeable c) { try { c.close(); } catch (Exception e) {} }
I would always go for the first example.
If close were to throw an exception (in practice that will never happen for a FileReader), wouldn't the standard way of handling that be to throw an exception appropriate to the caller? The close exception almost certainly trumps any problem you had using the resource. The second method is probably more appropriate if your idea of exception handling is to call System.err.println.
There is an issue of how far exceptions should be thrown. ThreadDeath should always be rethrown, but any exception within finally would stop that. Similarly Error should throw further than RuntimeException and RuntimeException further than checked exceptions. If you really wanted to you could write code to follow these rules, and then abstract it with the "execute around" idiom.
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With