Exceptions and Exception Handling Errors all programs encounter error conditions: incorrect use of methods: incorrect or invalid parameter values (e.g. divide by zero, null pointers) resource exhaustion: out of memory, disk space, OS resources... external systems: 3rd party libraries, hardware interfaces... implementation limits: numerical limits, data structure size limits... programs must be robust, that is they must behave reasonably in the presence of errors ideally, programs exhibit graceful degradation, where they continue to function approximately as they would in the absence of errors. Unexceptional approaches many ways to handle errors special return values not an option if the range of the function covers all possible values inconvenient: almost every statement is accompanied by an if..then..else, and must provide a variable to store the value inconsistent method semantics global error code, e.g. lastError can be difficult to understand and debug global variables are easy to corrupt error code parameter requires extra space on the call stack can be cumbersome to use requires pass-by-reference The Exception Philosophy a method can terminate one of two ways: exceptionally or normally. a client programmer cannot ignore when a method terminates exceptionally when an exceptional circumstance arises in a method, it stops, and throws an exception. the caller can then catch the exception, and deal with it. A typical example In Java, arrays are objects. Thus they can throw exceptions, and they do! If you try to access the array at an invalid index (e.g. i < 0 || i > length ), the array will throw an exception. public class ExceptionExample { public static void main( String args[] ) { int someInts[] = new int[3]; for ( int i = 0;; i++ ) { try { someInts[i] = i; } catch ( IndexOutOfBoundsException e ) { // uh-oh! we went past the end of the array break; } } // end for } // end main } What is an exception? an exception is an object in Java, which hold information about the exceptional event all exceptions are subclasses of java.lang.Throwable three methods of general interest: String constructor, sets the explanation string toString() returns a string that explains the exceptional event printStackTrace() prints the call stack from when the exception occured (helpful in debugging) Checked and unchecked exceptions there are two types of exceptions in Java, checked and unchecked checked derived from java.lang.Exception methods must declare (at compile time) if they throw checked exceptions caller must handle all checked exceptions unchecked derived from java.lang.RuntimeException does not have to be handled by the caller Example of checked and unchecked exceptions public class CheckVsUnchecked { public void someMethod( InputStream in ) { // MUST put call to read() in a try block, or else compile error. // This is because IOException is a CHECKED exception try { in.read(); } catch ( IOException e ) { // caught it! } int fiveInts[] = new int[5]; // don't have to put this in a try block, because IndexOutOfBounds // is an UNCHECKED exception. We could still try-catch it though. fiveInts[6] = 100; } } How to throw an exception throwing an exception involves : determine the exceptional circumstance create an exception object of the desired type, and include the explanation message in the constructor throw the exception! if the exception is checked (most user defined exceptions are), you must also include in the method declaration the types of exceptions that can be thrown Throwing an exception: example public void anotherMethod() throws IOException { BarcodeReader reader = new BarcodeReader(); int checksum = reader.getCheckSum(); int calculatedChecksum = calculateCheckSum( reader.getCode() ); if ( checksum != calculatedChecksum ) { throw new IOException( “bad barcode, checksums don't match” ); } } How to catch an exception, and what to do with it once you've caught it catch exceptions using try-catch blocks. try-block wraps the method calls that may throw exceptions catch block(s) specify what to do depending on the type of the exception reflecting exceptions if your method catches an exception, it may throw another exception appropriate if your method can't fix (or safely ignore) the problem happens automatically if you don't use catch() masking exceptions when your method catches an exception, it can deal with the problem (or maybe ignore it, if we know that it is safe to do so), and not throw any more exceptions e.g. can use array-bounds checking instead of checking the loop counter*, and just continue normal processing after the catch-block * depending on how exception handling is implemented, this may be an expensive way to iterate through an array, or a very cheap way. Handling exceptions example public void exceptionalMethod( InputStream in ) throws IOException { int someInts[] = new int[5]; try { int x = in.read(); // can throw IOExceptions someInts[x] = x; // can throw ArrayIndexOutOfBoundsExceptions x = x / 0; // can throw ArithmeticExceptions } catch ( IndexOutOfBoundsException e ) { // reflect IndexOutOfBoundsExceptions as IOExceptions, for the // sake of the example (better to define a new exception type) throw new IOException( “Not really an IO problem: “ + e ); } catch ( ArithmeticException e ) { // mask divide-by-zero exceptions by just reporting them System.err.println( e ); } // implied reflection of IOExceptions from read(), because they // are uncaught } Be careful handling exceptions remember that a catch-block will handle any exception of the type declared. in this example, the code will erroneously assume that the search problem is fixed, which will not be true because the catch-block only fixes problems with y try { x = y[n]; i = Arrays.search( z, x ); } catch ( IndexOutOfBOundsException e ) { // deal with accessing y out of bounds } // here we assume all is well, but the catch won't fix problems // related to the search call. Finally after all of the catch-blocks, you can add a finally-block the finally block will always be executed, whether or not an exception occurs. usually this is used for clean-up and restore operations, such as releasing file handles or refreshing the screen. BEWARE: if an exception occurs inside a finally-block, it will clobber any other exceptions that have occured. This can cause you to lose exceptions. Defining your own exceptions decide if your exception should be checked or unchecked sub-class Exception or RuntimeException (respectively) override constructors: public class MyNewException extends Exception { public MyNewException() { super(); } public MyNewException( String s ) { super( s ); } } you can be more clever, and add other helpful constructors, usually that result in a call like super( someCleverMessage ); it is good style to name your exception <error_name>Exception When to use exceptions, and when not to exceptions should be used to eliminate complicated rules about what is valid input to a method another good use is to avoid returning “special values” to indicate errors from a method remember that exception handling can be expensive, so don't use them for local results, like when a search-loop finishes without finding a match Summary of exceptions in Java handle exceptions using: throw exceptions by: declaring types of exceptions to be thrown e.g. public int myMethod() throws IOException { try { ... } catch ( Exception e ) { // can refer to e in this block ... } finally { ... } creating and throwing instances of the exceptions e.g. throw new IOException( “error details” );