EXCEPTION HANDLING - point of error detection and point of error recovery often decoupled - exception handling - flexible mechanism - pass control from point of detection to competent recovery handler THROWING EXCEPTIONS - what a method should do when it detects an error condition - traditional solution - return a value that indicates whether it succeeded or failed - problematic - caller forgets to check return value: failure undetected - caller can't do anything about the failure - must also fail - must propagate to own caller - many method calls would need to be checked for failure - programs get hard to read - also: - how pass other return values? - if multiple methods in a chain of calls can fail, how know which one did? - exception handling mechanism - exceptions can't be overlooked - exceptions are sent directly to an exception handler, not necessarily the caller of the failed method - on error detection - throw an appropriate exception object - use throw statement - syntax: throw - look for appropriate exception class - many provided by Java library - should describe error situation - current method terminates immediately - execution continues with an exception handler - e.g. throw new Exception("Description of what went wrong"); CHECKED AND UNCHECKED EXCEPTIONS - what happens when you call a method that throws an exception - depends on whether the exception is checked or unchecked - compiler - unchecked: compiler does not require you to keep track of - checked - compiler ensures not ignored - must tell compiler what you are going to do about the exception if it is thrown - why happens - unchecked - your fault - compiler does not require you to handle because if you program correctly, you won't encounter them - checked - likely to occur at times, no matter how careful you are - compiler insists that you handle because you cannot prevent with good programming - how to tell them apart - hierarchy: - Throwable: Error, Exception - Exception: RuntimeException - Error - fatal errors - happen rarely - beyond your control - unchecked: descendants of RuntimeException - checked - all other descendents of Exception - majority deal with IO - what to tell compiler for checked exceptions - aware of exception and want method to be terminated when it occurs - signal to the caller that it may encounter that exception (must also either handle or propagate) - tag the method with a throws specifier syntax: throws - e.g. public int read(String filename) throws FileNotFoundException, NumberFormatException { FileReader reader = new FileReader(filename); Scanner in = new Scanner(reader); String input = in.next(); int value = Integer.parseInt(input); return value; } - throws multiple different exceptions - use comma delimited list in throws clause - remember that different means have no common ancestor in the inheritance hierarchy - e.g. ArithmeticException and ClassCast Exception both extend RuntimeException so they are different, but IllegalArgumentException and NumberFormatException are not different because NumberFormatException extends IllegalArgumentException - make possible for exception to be processed by competent handler: method that does know how to communicate with the user or take other remedial action handle - handle exception (next): best not unless you know how to fix the situation CATCHING EXCEPTIONS - unhandled exception is thrown - error message printed - program terminates - every exception that your program might throw should be handled somewhere in your program - try/catch statement - syntax: try { } catch ( ) { } ... - try block contains one or more statements that may cause an exception - catch clause - contains the handler for an exception type - have one for each type of exception that you want to be handled differently - exception object contains reference to object that was thrown - catch clause can analyze to find more details about failure - Exception::printStackTrace() prints the chain of method calls that led to the exception - if exception is thrown - rest of instructions in try block are skipped - first catch block that matches exception type (or ancestor of exception type) is executed - list from most specific to most general - if the type matches none of the catch blocks, it is not caught - contents of catch clause - inform the user of the source of problems - better: give the user another chance to provide correct input - e.g. try { String filename = ...; FileReader reader = new FileReader(filename); Scanner in = new Scanner(reader); String input = in.next(); int value = Integer.parseInt(input); } catch (IOException ioe) { // FileNotFoundException extends IOException, so it's caught here ioe.printStackTrace(); } catch (NumberFormatException nfe) { System.out.println("Input was not a number"); } - throw early, catch late - better to throw an exception than to come up with an imperfect fix - method should only catch an exception if it can really remedy the situation, otherwise, should propagate - do not squelch exceptions - compiler complains if don't specify a handler for a checked exception - don't write a do-nothing try-catch block - exceptions were designed to report problems to a competent handler - hides an error condition that could be serious THE FINALLY CLAUSE - take some action whether or not an exception is thrown - finally clause after try block - syntax: try { } finally { } - normal case: executed after the try block successfully completes - exception is thrown: finally block is executed before the exception is passed to its handler - use whenever need to ensure cleanup occurs regardless of how method exits - finally clause after catch block: executes - after completing the last statement of the try block - after completing the last statement of a catch clause, if this catch block caught an exception - when an exception is thrown in the try block and not caught - e.g. try { FileReader reader = new FileReader(filename); // Read input } catch (IOException ioe) { // Handle exception } finally { reader.close(); } DESIGNING YOUR OWN EXCEPTION TYPES - do throw specific exceptions - choose an exception class that describes the situation as closely as possible - avoid catch blocks catching exceptions caused by other events (especially caused when have common ancestor) - if standard library does not have an exception class that describes your particular error condition well enough, define a new exception class - design your own exception class - decide whether it is checked or unchecked - checked - fault of some external event - extend Exception class - unchecked - fault of the programmer - extend RuntimeException class - provide two constructors - default constructor - constructor that accepts a message string - parameter describes the reason for the exception - can be retrieved via the getMessage method - should include a call to super(); - e.g. public class InsufficientFundsException extends RuntimeException { public InsuffiecientFundsException() {} public InsufficientFundsException(String message) { super(message); } } try { throw new InsufficientFundsException("Oh no!"); } catch (RuntimeException re) { System.out.println(re.getMessage()); // outputs Oh no! } DESIGNING A PROGRAM THAT UTILIZES EXCEPTIONS - identify what can go wrong - decide who can detect the faults - decide which exceptions can be thrown if using library methods that throw exceptions - decide whether need to throw own exceptions - decide which method can remedy the faults that the exceptions report - separation between error detection and error handling