**Exception Handling** !!! The exception handling features in the Java language provide a mechanism for gracefully recovering from a wide variety of unexpected situations in your code. Even if you've never heard of exceptions in Java, if you do much Java software development, you've likely encountered an exception of some sort. Program "crashes" are often the result of "an exception being thrown." When this happens, something like this is displayed to the console: ~~~~ Exception in thread "main" java.lang.NullPointerException at lecture.Driver.main(Driver.java:19) ~~~~ The exception handling features in the Java language provide a mechanism for gracefully recovering from a wide variety of unexpected situations in your code. In the first example, I tried to call a method using a reference that was assigned to null. Since it wasn't referring to an actual object, it was not possible to execute the method. At that point, the normal flow of the program is interrupted by an exception being thrown. In this case, I didn't do anything to handle the exception. As a result, the exception was thrown all the way back the the JVM (Java Virtual Machine) which then displayed the stack trace. The stack trace is a list of all of the method calls that took place before the exception was thrown. In this case, the exception was thrown from `main` (on line 19). Here is another example of an exception being thrown: ~~~~ Exception in thread "main" java.lang.NumberFormatException: For input string: "not an integer" at java.lang.NumberFormatException.forInputString(Unknown Source) at java.lang.Integer.parseInt(Unknown Source) at java.lang.Integer.parseInt(Unknown Source) at edu.msoe.se1021.YOURLOGIN.Horse.calculatePrice(Horse.java:134) at edu.msoe.se1021.YOURLOGIN.Lab4.displayMarketPrice(Lab4.java:74) at edu.msoe.se1021.YOURLOGIN.Lab4.main(Lab4.java:61) ~~~~ In this case, I called `Integer.parseInt` with "not an integer" as the argument. Of course, this cannot be converted/parsed into an integer. So what should we do? One option would be to just ignore the error (silently fail). If we did this, the `parseInt` method would still need to return something. What should we return? Another option would be to just give up and stop the program (that's essentially what happened here). If you look at the stack trace displayed above, you can see that the exception was thrown in the `Integer.parseInt` method which was called by the `Horse.calculatePrice` which was called by the `Lab4.displayMarketPrice` method which was called by the `Lab4.main` method. The stack trace also includes the line numbers on which the each method was called. This helps the developer track down the source of the exception. Depending on the design of our application, we may want to correct for this incorrect behavior in the `Horse.calculatePrice` method or `Lab4.displayMarketPrice` method or the `Lab4.main` method. The exception handling mechanism in Java provides just the flexibility we need in order to handle error conditions that may be encountered (bad user input, missing file, no network connection, etc...) in a place that makes sense to us. # Exceptions To summarize the discussion above: * An **exception** represents a condition in which something unexpected/abnormal has occurred. * This condition may occur during the normal execution of a program, e.g., ~~~~ Java int x=Integer.parseInt("1.234"); ~~~~ * When an exception occurs, the normal flow of the program is terminated. * Normal program flow is terminated by `throw`ing and exception. * Once a exception has been thrown, program flow works backwards through the various method calls currently on the stack until the exception is caught. * An exception is caught by an exception handling routine. * We can provide exception handling routines or not. * If no exception handling routines are provided, the Java Virtual Machine will **catch** and handle the exception. * In order to **catch** an exception, we need to be watching for an exception to be thrown. * We watch for exceptions using a **try** block. Consider the following code snippet: ~~~~ Java String input = JOptionPane.showInputDialog(null, "How old are you (in years)"); int age; try { age = Integer.parseInt(input); JOptionPane.showMessageDialog(null, "I'm guessing you'll be " + (age+1) + " next year"); } catch (NumberFormatException e) { JOptionPane.showMessageDialog(null, "Error! You should enter an integer value"); } ~~~~ If we enter something other than an integer, the program will display the error message, otherwise it will "guess" how old the user will be next year. ## try block * Code between curly braces following a **try** statement is part of what we call a **try block**. * If, at any time, an exception is thrown while we are in the try block, execution of the code within the try block is immediately halted. Program flow is transferred to the end of the try block. * Note: an exception can be encountered either by an explicit **throw** command within the try block or as a result of an un-handled exception thrown by a method which was called within the try block. In the above example, the exception was thrown by the parseInt method and was left unhandled. ## catch blocks * Code between curly braces following a **catch** statement is part of what we call a **catch block**. * A catch block is executed if 1. an exception has been encountered in the try block immediately preceding it and 1. the type of exception encountered matches the type of exception being caught. * The type of exception a catch block catches is specified in parentheses after the catch statement. In the above example, the catch block catches [NumberFormatException](http://javadoc.taylorial.com/java.base/lang/NumberFormatException.html) type exceptions. * Only the first matching catch block after a try block will be executed. * If no exceptions were encountered during the execution of a try block, the catch block(s) after the try block are ignored. Program flow continues with the statement following the try-catch statement. * If an exception is encountered, but no matching catch block is present, program control reverts to the calling method. # Types of Exceptions * In order for an exception to be thrown, it must be an object from the [Throwable](http://javadoc.taylorial.com/java.base/lang/Throwable.html) class, or one of its subclasses. * The [Throwable](http://javadoc.taylorial.com/java.base/lang/Throwable.html) class has two subclasses: 1. [Error](http://javadoc.taylorial.com/java.base/lang/Error.html) 1. [Exception](http://javadoc.taylorial.com/java.base/lang/Exception.html) * Recall that the type of exception being caught must be specified in the catch block's parameter list. * There are many different types of exceptions. After studying the [Throwable](http://javadoc.taylorial.com/java.base/lang/Throwable.html), [Error](http://javadoc.taylorial.com/java.base/lang/Error.html), and [Exception](http://javadoc.taylorial.com/java.base/lang/Exception.html) classes we can conclude that: * [Error](http://javadoc.taylorial.com/java.base/lang/Error.html) and [Exception](http://javadoc.taylorial.com/java.base/lang/Exception.html) types are specializations of the [Throwable](http://javadoc.taylorial.com/java.base/lang/Throwable.html) type. * [Exception](http://javadoc.taylorial.com/java.base/lang/Exception.html) has all of the characteristics (attributes/behaviors) of a [Throwable](http://javadoc.taylorial.com/java.base/lang/Throwable.html) object, but [Exception](http://javadoc.taylorial.com/java.base/lang/Exception.html) may specialize (re-implement) some of these characteristics or add other characteristics that are shared by all [Exception](http://javadoc.taylorial.com/java.base/lang/Exception.html) instances but don't apply to [Throwable](http://javadoc.taylorial.com/java.base/lang/Throwable.html) instances. * The [java.lang](http://javadoc.taylorial.com/java.base/lang/package-summary.html) package provides a number of subclasses (and subsubclasses, etc) of the [Exception](http://javadoc.taylorial.com/java.base/lang/Exception.html) class. * Objects from any of these subclasses can be thrown. * The diagram below shows some of the types that can be thrown. ![Figure [exceptions]: Exception Class Hierarchy](exceptionUML.png) # Handling Exceptions * When an object from the [Error](http://javadoc.taylorial.com/java.base/lang/Error.html) class is thrown, it represents a serious problem and normally should not be caught. * When an object from the [Exception](http://javadoc.taylorial.com/java.base/lang/Exception.html) class, or one of its subclasses, is thrown, it typically should be caught and handled. * The type of exception a catch block catches is specified in parentheses after the catch statement. + A thrown exception will be caught if it is the same type or a subtype of the type specified in parentheses. + For example, if a [NumberFormatException](http://javadoc.taylorial.com/java.base/lang/NumberFormatException.html), it would be caught by the following catch block: ~~~~ Java catch (Exception e) { // ... } ~~~~ since [Exception](http://javadoc.taylorial.com/java.base/lang/Exception.html) is a superclass of [NumberFormatException](http://javadoc.taylorial.com/java.base/lang/NumberFormatException.html). * Once caught, methods from the [Throwable](http://javadoc.taylorial.com/java.base/lang/Throwable.html) class provide information about the exception that was thrown: + The [getMessage()](http://javadoc.taylorial.com/java.base/lang/Throwable.html#getMessage%28%29) method returns a descriptive string. + The [printStackTrace()](http://javadoc.taylorial.com/java.base/lang/Throwable.html#printStackTrace%28%29) method prints all of the methods on the stack, i.e., all of the still active methods called prior to encountering the exception. * Be sure to catch more specialized exception types (subclasses) first since once a matching catch block is found, all other catch blocks are ignored. * If a thrown exception is not caught, anywhere in the program, the Java Virtual Machine (JVM) catches it. The JVM handles exceptions by calling [printStackTrace()](http://javadoc.taylorial.com/java.base/lang/Throwable.html#printStackTrace%28%29) and then terminating the program. ## Recapping Consider the following code: ~~~~ Java String input = JOptionPane.showInputDialog(null, "How old are you (in years)"); int age; try { age = Integer.parseInt(input); JOptionPane.showMessageDialog(null, "I'm guessing you'll be " + (age+1) + " next year"); } catch (NumberFormatException e) { JOptionPane.showMessageDialog(null, "Error! You should enter an integer value"); } catch (RuntimeException e) { JOptionPane.showMessageDialog(null, "Error! Some runtime exception other than NumberFormatException was thrown"); JOptionPane.showMessageDialog(null, "Hint: " + e.getMessage()); return; } JOptionPane.showMessageDialog(null, "No worries. Either way we'll continue on with our program"); ~~~~ * Recall that, if no exception occurs, all of the code except for the catch blocks will be executed. * If an exception is thrown while in the try block, + The first catch block will be executed if the exception thrown is of type [NumberFormatException](http://javadoc.taylorial.com/java.base/lang/NumberFormatException.html). Once the catch block finishes executing, program execution continues after the last catch block. + The second catch block will be executed if the exception thrown is of type [RuntimeException](http://javadoc.taylorial.com/java.base/lang/RuntimeException.html) or any subclass of [RuntimeException](http://javadoc.taylorial.com/java.base/lang/RuntimeException.html) other than [NumberFormatException](http://javadoc.taylorial.com/java.base/lang/NumberFormatException.html) (because that exception would have already been caught by the first catch block). If the second catch block is executed, program control is returned to the calling method at the end of the catch block, so the "No worries" dialog will not be displayed. + If no catch block matches the exception thrown, execution of the current method is terminated and the exception is thrown to the calling method (which can either catch it or propagate the exception to the method that called it). ## throw statement * We can explicitly throw exceptions using the following to steps: 1. Instantiate the appropriate [Throwable](http://javadoc.taylorial.com/java.base/lang/Throwable.html) object. 1. **throw** a reference to that object. * An object is said to be a [Throwable](http://javadoc.taylorial.com/java.base/lang/Throwable.html) object if it is an instance of the [Throwable](http://javadoc.taylorial.com/java.base/lang/Throwable.html) class or one of [Throwable](http://javadoc.taylorial.com/java.base/lang/Throwable.html)'s subclasses. * [Exception](http://javadoc.taylorial.com/java.base/lang/Exception.html) is a subclass of [Throwable](http://javadoc.taylorial.com/java.base/lang/Throwable.html). * Here is what it looks like in Java: ~~~~ Java throw new Exception("Info about the exception"); ~~~~ Modifying the previous code to throw an exception if the user entered an age greater than 120 would look like this: ~~~~ Java String input = JOptionPane.showInputDialog(null, "How old are you (in years)"); int age; try { age = Integer.parseInt(input); if(age>120) { throw new Exception("Out of bounds"); } JOptionPane.showMessageDialog(null, "I'm guessing you'll be " + (age+1) + " next year"); } catch (NumberFormatException e) { JOptionPane.showMessageDialog(null, "Error! You should enter an integer value"); } catch (RuntimeException e) { JOptionPane.showMessageDialog(null, "Error! Some runtime exception other than NumberFormatException was thrown"); JOptionPane.showMessageDialog(null, "Hint: " + e.getMessage()); return; } JOptionPane.showMessageDialog(null, "No worries. Either way we'll continue on with our program"); ~~~~ ## Exception throwers * A method is said to be an exception thrower if it has the potential to throw an exception (directly or indirectly). * Such a method can be a: + Catcher -- if it catches a thrown exception, + Propagator -- if it leaves a exception uncaught (so that it propagates to the calling method, or + Both if it does some of each. ## Unchecked Exception * Some exceptions are not allowed to propagate back to the JVM, i.e., they must be caught by your code. * A *checked exception* is an exception that is checked at compile time. * Objects from the [RuntimeException](http://javadoc.taylorial.com/java.base/lang/RuntimeException.html) or one of its subclasses are *unchecked* exceptions. + Do not need to be caught by your code. + Are detected only at runtime. * Only [RuntimeException](http://javadoc.taylorial.com/java.base/lang/RuntimeException.html)s can be left unchecked. * In order to propagate a checked exception, the method propagating the exception must explicitly indicate that it may throw a checked exception. + To indicate that a method may throw a checked exception, the method's header must include a list of checked exceptions that it may throw. + The syntax makes use of the **throws** keyword as follows: ~~~~ Java void someMethod() throws IOException { // ... } ~~~~ * The exception classes shown in yellow in the figure above are all checked exceptions. That is, the compiler checks to make sure if there is a potential that any of those types of exceptions are thrown, they must be handled. * Use of the **throws** keyword is optional for [RuntimeException](http://javadoc.taylorial.com/java.base/lang/RuntimeException.html)s. ## The finally Block * A **finally** block may be used in conjunction with a **try** block. * Code within a **finally** block is executed regardless of whether an exception was thrown within the **try** block that it is associated with. * The **finally** block is discussed on the [File IO](FileIO.html) page.