CS 302 Lecture 10 and 21 Author: Marina Polishchuk Date: April 2005 ========================================================== EXCEPTION HANDLING So far, we haven't asked you to do much error checking in this class. Currently, you know two ways to handle errors that may arise when your program is running. (?) 1. Assume they won't happen--annotate methods with preconditions and postconditions. 2. Use if statements to ensure that only proper inputs are processed. Ex: the BankAccount's deposit(double amt) method should only allow a positive deposit: (1) public void deposit(double amt) { if(amt > 0 ) { balance += amt; } } (2) /*@precondition: amt > 0 */ public void deposit(double amt) { balance += amt; } ============================================================================================== This week we're learning a third way to handle errors, which is to raise (throw) an exception. Informally, this means your program throws up its hands and says "i don't know what to do: let whoever is responsible for the erroneous inputs try to handle this error". Ex: (3) public void deposit(double amt) throws Exception { if(amt <= 0) { throw new Exception("Someone is trying to deposit a negative amt"); } balance += amt; } The above is an example of an exception that's raised by the programmer him/herself. There are many other types of exceptions already built into Java that deal with common error conditions such as i/o errors or arithmetic errors. [see p. 554 in your textbook] So, what happens if an exception is thrown? [Note: this describes the scenario when one does *not* include a try/catch block] - No further statements in the method are executed - The Exception object just thrown is *propagated* through the *call stack* until someone provides directions (i.e. code) for handling the error. Definition: *call stack*: All methods that have been called but have not yet terminated, starting from the current method and ending with main(). You've seen this in the eclipse debugger. In the ExceptionExample.java handout, each "example output" after the program crash prints the call stack which the exception object "visited" before the program crashed. - If the java application does not provide special code to handle this exception, then the program exits and reports the exception (via standard output--see ExceptionExample.java). ================================================================================================ There are two types of exceptions in Java: *checked* and *unchecked*. +++++++++++ A *checked* exception is one that the compiler is aware of. If your method may throw a checked exception, the compiler makes sure that you either: 1) Include error handling code that will *catch* this exception inside your method. 2) Declare (as part of the method signature) that your method may throw this type of checked exception. In this case, the compiler makes sure that any other methods that call your method satisfy condition (1) or (2) as well. The reason Java includes checked exceptions is to allow better program control of external circumstances, such as failing i/o devices or missing external data. Examples: - IOExceptions: file i/o, some console i/o - ? ++++++++++++ An *unchecked* exception is not checked:). The compiler will not force you to create error handling code, but in most cases it is a good idea to do so. One difference between checked vs. unchecked exceptions is that checked exceptions are those that the programmer cannot prevent from being thrown (e.g., we can't try to fix disk errors from w/in our Java application). Unchecked exceptions are (in theory, i.e. by definition) thrown solely due to the programmer's mistakes/omission for invalid data handling. With this in mind, there are two ways one might handle unchecked exceptions. 1) Include a try-catch block (or a try-catch-finally block if needed). Put the part of your code that may throw an exception inside the try block, and put any error handling code inside the catch block. The catch block is specific to the kind of exception object thrown inside your try block, though specifying objects of type "Exception" will catch every possible exception type [refer to page 554]. The syntax of try-catch blocks is illustrated in ExceptionHandling.java. 2) Include checks prior to code that may throw an exception (e.g., via if statements). This ensures that your code is only executed if the associated data is valid. The alternatives for errors shown in ExceptionHandling.java are shown in ExceptionAlternate.java. For instance, to avoid an ArithmeticException that results from divide-by-zero, your code might look like: int x; //... if(x!=0 { double j = (double)20/x; } OR int x; //... try { double j = (double)20/x; } catch(ArithmeticException ae) { //handle the error } ===================================================================================================== The try-catch-finally syntax has several subtleties. 1. A single try block may have either: - ZERO OR MORE associated catch blocks, and one finally block. - ONE or more associated catch block The finally block is *always* executed, and either ZERO or ONE catch block is executed. 2. After leaving the try block (when an exception is thrown), the program attempts to find a corresponding catch block for the exception object thrown. It does so IN SEQUENTIAL ORDER of exception blocks within your code. Refer to ExceptionOrderings.java for examples of this feature. 3. The finally clause is intended for cleanup code in case an error occurs. It generally includes resource management for code that has been executed inside the try block. For example, if a file was opened for writing in the try block, and some data was written to it before an IOException, one might want to close the file in the finally clause so that its contents are saved upon exit. See ExceptionOrderings.java for details. ===================================================================================================== Defining Your Own Exceptions This can be done by extending (via "extend") the Exception class. Usually, this is done for more complex applications that may have a variety of rather different error conditions. Extending the Exception class (or, in general, the Throwable class) allows the subclass to be thrown via a "throw" statement and caught in a catch block. Refer to ExceptionSpecific.java for a short example [another is on text pg. 563] =====================================================================================================