Java supports multiple non-mandatory catch blocks and a finally block. There are strict rules to be followed to decide the order and presence of these blocks. We have already looked at introduction to exceptions and basic try-catch-finally-mechanism. We now look at the control flow of these three blocks.
Control Flow of try-catch-finally Blocks
There are multiple usage patterns of try-catch-finally block. We now analyze them one by one starting with the simplest.
One try and One catch
This is is the simplest usage pattern.Java
1 2 3 4 5 6 7 8 9 10 11 12 13 14 | try { punish(aCitizen); punish(aPolitician); System.out.println("It's the 99.9% politicians that give a bad name to other politicians"); } catch(Exception e) { System.out.println("A politician is above law."); } // continue with control flow |
The above code block is telling Java to execute code in the try block and if it encounters an Exception to execute the code in catch block. The control flow moves from the try block to catch block as soon as exception is encountered. In the above example, punish(aCitizen) executes fine, when punish(aPolitician) throws an exception the control flow moves from the try block to catch block. The System.out.println() in the try block is never executed.
Remember that catch block is executed only when exception occurs. Otherwise, the control flow proceeds from the try block to the statement immediately after catch block.
One try and Multiple catch
Java allows you to specify multiple catch blocks for a try block. There is one golden rule that compiler forces you to adhere to in this regard. The catch blocks must be ordered based on the hierarchy. catch block for a specific exception must be placed before catch block for a more general exception. We will be covering exception hierarchies in great details in the next lesson.Java
1 2 3 4 5 6 7 8 9 | public static void main(String []args){ try { throw new Exception("Multiple catch block demo"); } catch (Exception e) { System.err.println("I got exception: " + e); } catch(Throwable t) { System.err.println("I got throwable: " + t); } } |
The above code prints
1 | I got exception: java.lang.Exception: Multiple catch block demo |
Note that it is compile time error to try to reverse the order of catch blocks. Since Exception is a sub-class of Throwable, the catch block of Exception must be placed before that of Throwable. The reason for this rule has to do with is-a relationship between Throwable and Exception. Exception is-a Throwable. If you place Throwable‘s catch block before Exception‘s Java has no way of deciding which block it must execute. We will cover the is-a relationship further in our lessons on object orientd programming.
A try and a finally
Depending on how bleeding-edge your coding practices are, this may either be the way to write code or a big no-no.
Traditionally, Java programmers never write code that has just a try and finally. The conventional wisdom states that “catch the exception closest to its point of origin.” Therefore, in the old-school Java, you would always write a catch block for try.
Not writing a catch block lets the exception propagate. This propagation can be handled elsewhere. This is the latest wave in exception handling. You catch only what can be meaningfully handled.
Here is sample code for this usage pattern.Java
1 2 3 4 5 6 7 | public static void main(String []args) throws Exception{ try { throw new Exception("try-finally block demo"); } finally { System.out.println("In finally in spite of exception"); } } |
The output of the above code is
1 2 3 | In finally in spite of exception Exception in thread "main" java.lang.Exception: try-finally block demo at HelloWorld.main(HelloWorld.java:5) |
One try, multiple catch and a finally
This is the most complete variant that specifies all three – try, catch and finally. There are no additional rules apart from the ones that we have covered. The following code demonstrates this usage pattern.
1 2 3 4 5 6 7 8 9 10 11 12 | public static void main(String []args) throws Exception{ try { throw new Exception("Multiple catch and finally block demo"); }catch (Exception e) { System.err.println("I got exception: " + e); } catch(Throwable t) { System.err.println("I got throwable: " + t); } finally { System.out.println("In finally in spite of exception"); } } |
The output of the above code is
1 2 | I got exception: java.lang.Exception: Multiple catch and finally block demo In finally in spite of exception |
Nested try-catch-finally
Java allows you to nest a try-catch-block within other try, catch and finally blocks. For example you can have a try-catch-finally block inside a catch or a finally or within other try block
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 | public static void main(String []args) throws Exception{ try { try { System.out.println("Nesting a try within try"); throw new Throwable("A throwable"); } catch(Throwable t) { System.out.println("Gulping a throwable: " + t); } finally { System.out.println("From finally in nested try\n"); } throw new Exception("Multiple nested catch and finally block demo"); }catch (Exception e) { try {} // a dummy try finally { System.err.println("From finally in catch: I got exception: " + e); } } catch(Throwable t) { System.err.println("I got throwable: " + t); } finally { try { System.out.println("From try in finally in spite of exception"); } finally {} // dummy finally } } |
The output of this code is
1 2 3 4 5 6 | Nesting a try within try Gulping a throwable: java.lang.Throwable: A throwable From finally in nested try From finally in catch: I got exception: java.lang.Exception: Multiple nested catch and finally block demo From try in finally in spite of exception |
Having seen the rules for usage of try, catch and finally we will summarize all the rules in the next article.