Exceptions and exception handling are an important part in most applications. And modern programming languages support exceptions very well. Most of them provide try/catch/finally clauses for developers to handle exceptions. Here we talk about how to write try/catch/finally clauses in a more elegant way.
Here, we take I/O operations as our illustrated example, because I/O conerns three important steps when using: initialization, exception handing and cleanup.
Generally, some programmer might write like this:
// Declaration of objects InputStream input = null; OutputStream output = null; try { // Initialization input and output input = new FileInputStream("readme.txt"); output = new FileOutputStream("ic_card.txt"); // Operations int seg = 0; byte[] buf = new byte[4096]; while ((seg = input.read(buf)) != -1) { output.write(buf, 0, seg); } } catch (FileNotFoundException e) { // handling exception } catch (IOException e) { // handling exception } finally { // cleanup try { if (input != null) { input.close(); } if (output != null) { output.close(); } } catch (IOException e) { // handling exception } }Such style has the following problems:
try { // Declarations InputStream input = null; OutputStream output = null; try { // Initialization input and output input = new FileInputStream("readme.txt"); output = new FileOutputStream("ic_card.txt"); // Operations int seg = 0; byte[] buf = new byte[4096]; while ((seg = input.read(buf)) != -1) { output.write(buf, 0, seg); } } finally { // cleanup codes if (input != null) { input.close(); } if (output != null) { output.close(); } } } catch (FileNotFoundException e) { // handling exception } catch (IOException e) { // handling exception }
This try/finally try/catch style is superior to previous version is because, it finishes all the tasks: declaration, initialization, operations and cleanup. All blocks are inside big try/catch so that all exceptions are get caught; Cleanup is inside try/finally so that we ensure to release taken resources. It also looks elegant.
Such try/finally try/catch clauses, however, have a fatal defect that exceptions could be ignored and lost. In try/finally, finally block gets executed even if when exceptions are thrown in try block. If finally block also throws exceptions, ones thrown in try blocks are ignored and lost. Outer catch clauses will never catch them. In all, this style might not catch all exceptions thrown in try blocks.
You can apply this try/finally try/catch style when:
// Delcarations try { // Initializations // Operations } catch { // handling exceptions } finally { // cleanup }