Topic 6: Exceptions Exceptions are a Java mechanism for dealing with errors & unusual situations Goals: learn how to... think about different responses to errors write code that catches exceptions write code that throws exceptions create your own exception types 1
Quote From Java Tutorial "If there's a golden rule of programming it's this: Errors occur in software programs. This we know. But what really matters is what happens after the error occurs. How is the error handled? Who handles it? Can the program recover, or should it just die?" 2
Exceptions Exception: alarm going off when something unusual happens Usually an error (divide by zero, file not found) Sometimes unusual, but not erroneous (example: end of file) Advantages of using exceptions: separate normal code from error-handling code lets you defer decision about how to handle error up the call stack provides hierarchy of errors 3
Exception Class In Java, almost everything is an object An exception is an object of class Exception contains information about what happened, where it happened, and program state at the time most is for Java VM, not programmer What's important for the programmer: what kind of exception is it? the message inside (a String) 4
Exception Classes And many, many more... 5
Exception Messages an exception object contains a message (type String) The message describes the error/unusual circumstance Unfortunately: API documentation often doesn't tell you what will be in messages for different Exception classes... Good practice: When you throw an exception, include a message describing what happened. Program can display the message to the user. Also useful to programmer if program aborts. 6
Example: NumberFormatException to convert a String to an int: int i = Integer.parseInt(s); if s is not in int format, this call throws a NumberFormatException How did I know that? Says so in API documentation for the method When you write a method that can throw an exception, ***document it in the method's header comment! (What kind of exception and under what circumstances.) demo... 7
try { <code that might throw a NumberFormatException> catch (NumberFormatException e) { <code to execute if you get a NumberFormatException> add a try/catch to demo... Catching An Exception 8
Letting Exceptions Propagate Up You don't have to catch an exception in the same method as it was thrown Demo program: CatchDemo main domath getnumber parseint Number Format Exception 9
Multiple Catches try { // code that might throw exceptions catch (ArithmeticException e) { System.out.println("arithmetic exception"); catch (NumberFormatException e) { System.out.println("number format exception"); catch (NullPointerException e) { System.out.println("null pointer exception"); catch (RuntimeException e) { System.out.println("some other runtime exception"); Java tries each catch in order until it finds a match No match exception propagates outwards and up the call stack 10
Order is Important! try { // code that might throw exceptions catch (ArithmeticException e) { System.out.println("arithmetic exception"); catch (RuntimeException e) { // superclass of other 2 System.out.println("some other runtime exception"); catch (NumberFormatException e) { System.out.println("number format exception"); if try code throws NumberFormatException: caught by second catch Third catch clause is unreachable 11
Throw Statement to throw an exception on purpose: throw <exception object>; Exceptions have two constructors: new Exception() // no message new Exception("explanation of error") All Exception subclasses in API have similar constructors usually create and throw in one statement: throw new ArithmeticException(); throw new IOException("file input.txt"); 12
Old Quiz Question try { for (int i = 0; i < 10; i++) { try { if (i == 3) throw new NullPointerException(); if (i == 6) throw new ArithmeticException(); System.out.print(i + " "); // end try catch (NullPointerException e) { System.out.print("null "); // end catch // end for // end try catch (ArithmeticException e) { System.out.print("arithmetic "); // end catch System.out.println("done"); 13
"Throws" Clause When a method may throw an exception, should use a "throws" clause in header void write(int b) throws IOException {... Informs compiler that call of method may cause exception Also good documentation for reader. Also document exceptions in method headers: /***************************************** * This method does blah, blah, blah * Parameters: * a:... * b:... * Return value:... * Exceptions: throws IOException if input file * does not exist ****************************************/ 14
"Catch or Specify" Rule Two ways to write code that can throw an exception: use a "throw" statement call a method that can throw an exception You must do one of the following: catch the exception inside that same method specify that the method may throw an exception (i.e. add a "throws" clause) If you do neither, you get a compiler error 15
Loophole for RuntimeException Special case: if method throws a RuntimeException (or subclass of RuntimeException) don't have to use throws clause ("unchecked exceptions") All other exceptions: throws clause required. ("checked exceptions") Rationale: RuntimeException is for common runtime errors, many methods might throw (divide by zero, null pointer, array index, etc.) Don't document obvious RuntimeExceptions that may be caused by bugs in code (divide by zero, null pointer, etc.) Do document runtime exceptions such as NumberFormatException which may reflect error in input 16
Stack Example recall error conditions in stacks: pop from empty stack push onto full stack for ArrayStack Example code aborted program Better option: raise an exception Advantage: caller can decide what to do public int pop() throws Exception { if (topindex == -1) { throw new Exception("empty stack"); int result = elements[topindex]; topindex--; return result; // end pop 17
Improvement Previous example is OK, but not ideal Caller must catch all exceptions & test message. Better way: declare own exception type. Catch block can catch stack exceptions specifically public class EmptyStackException extends Exception { public EmptyStackException(String msg) { super(msg); // end constructor public EmptyStackException() { super(); // or use a default message // end constructor // end EmptyStackException 18
Organizing Stack Exceptions Create another exception class for adding to a full stack: FullStackException Make both exception classes subclasses of a general class: StackException StackException EmptyStackException FullStackException Advantage: can catch all stack-related exceptions together: catch (StackException e) 19
Modified Stack Interface public interface Stack { public void push(int value) throws FullStackException; public int pop() throws EmptyStackException; public boolean isempty(); 20
Modified pop from ArrayStack public int pop() throws EmptyStackException { if (topindex == -1) { throw new EmptyStackException( "attempt to pop from empty array stack"); int result = elements[topindex]; topindex--; return result; // end pop 21
How to Use Stacks With Exceptions (1) Simplest case: You believe your code will never make a stack error, and/or you don't care if the program aborts when there's an error Surround all stack code with a try/catch, catch will abort: try { Stack s = new LinkedStack();... use s... catch (StackException e) { System.out.println("Stack error: " + e.getmessage()); System.exit(1); ; 22
How to Use Stacks With Exceptions (2) Exceptions give you the flexibility to recover from errors try { teststack.push("new stack element"); catch (FullStackException e) { System.out.println( "Error: stack is full; couldn't push"); // end catch // Program continues, even if error occurred 23
Consequences of Exceptions Now Stack methods can throw exceptions. Calling methods must deal with them: catch them or have "throws" clause Suppose method m pops something off a stack method m must do one of these things: 1. put the pop in a try block with a catch for EmptyStackException 2. include throws EmptyStackException in its header Consequence of #2: all methods that call m must in turn deal with the possible exception (catch or specify) 24
Is This a Bad Thing? Usually, no! At first, seems like a nuisance. But forces programmer to deal with the possibility of an empty stack error Program will be more robust. 25
Occasional Nuisances Consider this code: Stack s;... while (!s.isempty()) { int value = s.pop(); // do something with value // end while This code will never cause an EmptyStackException. But the compiler doesn't know this We must still write code to catch the exception. 26
Provide trivial handler: Solution try { Stack s = new LinkedStack(); // code that pushes integers onto s while (!s.isempty()) { int value = s.pop(); // do something with value // end while catch (EmptyStackException e) { System.out.println("Internal Error: " + + "empty stack in <method name>"); System.exit(1); 27
Temptation: RuntimeException We defined stack exceptions as direct subclasses of Exception. So they are "checked exceptions" must catch or specify. We could have defined them as subclasses of RuntimeException. Then we can ignore them, compiler won't complain. This is legal Java, but bad style. Leave RuntimeException for common runtime errors 28
Exceptions Are For Exceptional Cases public int arraysum(int arr[]) { int sum = 0; try { int i = 0; while (true) { sum += arr[i]; i++; // end while // end try catch (ArrayIndexOutOfBoundsException e) { System.out.println("sum = " + sum); // end catch // end arraysum Bad idea!!! Use loop condition instead: more efficient and more readable. Don't rely on exceptions when there's a simpler way to prevent or detect a problem. 29
Another Practice Problem public static void main(string args[]) { try { practice("124"); System.out.println("124 done"); practice("2468"); System.out.println("2468 done"); practice("35"); System.out.println("35 done"); practice("seventeen"); System.out.println("seventeen done"); practice("twenty5"); System.out.println("twenty5 done"); catch (NumberFormatException e) { System.out.println("format"); // end main public static void practice(string numstring) { int x = 0; try { x = Integer.parseInt(numString); endofterm(x); if (x % 2 == 0) // x is even System.out.println("even " + x); else throw new ArithmeticException(); catch (ArithmeticException e) { System.out.println("arith " + x); catch (NullPointerException e) { System.out.println("null pointer " + x); // end practice public static void endofterm(int number) { if (number > 200) throw new NullPointerException(); System.out.println("good " + number); // end endofterm 30