Exception Handling and Assertions James Brucker 1 Exceptions
Exception Handling and Assertions James Brucker 1
Exceptions q Exceptions are unusual events detected by the computer or software. n q An exception is not necessarily an error. Asynchronous exceptions can occur at any time, independent of the program execution. Example: hardware error, user terminates program q Synchronous exceptions occur in response to some action by the program. Example: subscript out-of-bounds, read error, stack overflow Q: Which type of exception can a program "catch" ? 2
Types of Exceptions Hardware Errors such as write to write-protected devices. n hardware failures are usually fatal n handled by hardware or OS, not application program. q Software Errors including access to invalid memory address, attempt to access non-existent file. q Language Violations (dynamic semantic errors): illegal array subscript, referencing null pointers. q User-defined (program-defined) conditions e. g. , a Parse. Exception thrown in a recursive-descent program. Java and C++ allow user to define and raise any "exception". q 3
What triggers exceptions? q q Hardware: n hardware may prevent writing to some devices (read-only) n restrict access to memory OS or Executor: n n n q Java VM detects null reference, I/O, and array bounds errors OS enforces file permissions Java Security Manager (raises Security. Exception) User program: n n a program can raise or throw exceptions as part of the code (C++, Java, Ada, . . . ). a function may "assert" conditions that should be true (for validating the software). If false, an exception is raised. 4
Exception Handler try { block-of-code; } catch (Exception. Type 1 e) { handler-code; } catch (Exception. Type 2 e) { handler-code; }. . . finally { code to always execute before continuing; } Stringbuffer = new String. Buffer(); try { while ( ( c = System. in. read() ) != 0 ) buffer. append(c); } catch (IOException e) { System. out. println("I/O error: " + e); } 5
Exception Handler (2) An exception handler is statically (lexically) bound to a block of code. q Unlike "lexically scoped" variables, the scope of an exception includes any function calls inside its block: q try { String line = buffered. Reader. read. Line( ); writer( line ); } catch ( IOException e ) { System. out. println("I/O error: "+e); } 6
Two Exception Handling Modes resumption: after the exception handler runs, the program continues at the point where the exception occurred. q termination: flow of execution branches to exception handler and does not return to the point of exception. q try { p = read( f. Handle ); process(p); } catch ( exception ) {. . . } do. Something. Else( ); Exception raised resumption termination 7
Exception Propagation Exception handlers form a stack, each with a scope. q When an exception occurs, the run-time must find an exception handler on the handler stack q it must "unwind" the call stack during the search. q sub A( ) { p = new int[-1]; bad_alloc raised } sub B( ) { Scope exception handler try { A( ); 05 -07 bad_cast 07 } catch( bad_cast ) {. . . } 10 -12 bad_alloc 10 } sub C( ) { try { B( ); } catch( bad_alloc ) {. . . } 8 }
Exception Handling is Expensive Runtime environment must locate first handler. q Unwind call chain and stack n locate return address of each stack frame and jump to it. n invoke "epilogue" (return) code for each function n branch to the exception handler q Recommendation: avoid exceptions in normal flow of execution. q Example (this is a homework problem): compare the speed of a "factorial" method that uses exceptions and a "factorial" that uses an "if" test to terminate recursion. 9
Exceptions in Java Exceptions are objects from subclasses of "Throwable". Throwable Exception Runtime. Exception • Index. Out. Of. Bounds IOException Error others Detected and thrown by Java • EOFException • Parse. Exception VM, such as out • Zip. Exception • user defined of-heap space • Null. Pointer • Class. Cast (bad cast) • many others (see API) • many others 10
Exceptions in C++ A C++ program can throw anything. Standard exception classes: exception logic_error length_error domain_error out_of_range invalid_argument runtime_error bad_alloc bad_cast range_error overflow_error underflow_error bad_exception bad_typeid ios_base: : failure 11
Why Use an Exception Hierarchy? 1. Makes exception collection extensible. /** Define an exception for stupid users */ public class Stupid. User. Exception extends Runtime. Exception { public Stupid. User. Exception( String msg ) { super( msg ); } } 12
Why Use an Exception Hierarchy? 2. Programmer can write multiple "catch" blocks arranged hierarchically. // read binary data from a file Data. Input. Stream din = new Data. Input. Stream(. . . ); try { count = din. read( bytearray ); process. Data( bytearray ); } catch ( EOFException eof ) { // no problem. . . just close file and continue } catch ( IOException ioe ) { // oops. . . something wrong err. println("I/O error: " + ioe); } catch ( Exception e ) { // process. Data( ) threw an exception 13
Two Types of Exceptions in Java Two categories of exceptions: q Checked Exceptions are exceptions that Java requires the program to either handle or explicitly acknowledge that it may generate this exception. Example: read. Data(String filename) throws. . . what? q Unchecked Exceptions: the program may provide an exception handler (try. . . catch) but is not required. n Unchecked Exceptions are for events that the programmer can avoid by careful programming. n would be tedious to require acknowledging all of them 14
Checked Exceptions in Java q Checked Exceptions include subclasses of n n IOException Clone. Not. Supported. Exception user-defined classes that extend Exception. q Programmer declares that a method "throws" an exception to a higher-level handler by writing: methodname(params) throws Some. Exception n read. Data(String filename) throws IOException { try { URL myurl = new URL("http: //www. ku. ac. th"); } catch (Malformed. URLException expt) {. . . } // other IOException is thrown by read. Data() 15
Unchecked Exceptions in Java Unchecked Exceptions: the program may provide an exception handler (try. . . catch) but is not required. q Unchecked Exceptions include subclasses of Error and Run. Time. Exception. q Methods should not use ". . . throws Some. Exception" for Unchecked Exceptions. q Reason: q n n Error conditions are beyond the control of the application. You should let the Java. VM handle them, or It would be too cumbersome to require every program to either "catch" or "throw" all Run. Time. Exceptions. For example, every object reference would require declaring or catching "Null. Pointer. Exception" ! 16
Exceptions Example What exceptions may this Java code throw? /* count the words in a file */ int word. Count( String filename ) { int count = 0; Input. Stream ins = new File. Input. Stream( filename ); Scanner scan = new Scanner( ins ); // read input lines while( scan. has. Next() ) { String line = scan. next. Line(); String [] words = line. split("\s"); // "word" must start with a letter for(int k=0; k<=words. length; k++) if ( Character. is. Letter( words[k]. char. At(0) ) ) count++; } return count; } 17
Exceptions Example: Solution If Java required you to declare every exception that a code might throw, this code would look like: /* count the words in a file */ int word. Count( String filename ) throws IOException, Null. Pointer. Exception, Illegal. State. Exception, No. Such. Element. Exception, Array. Index. Out. Of. Bounds. Exception, String. Index. Out. Of. Bounds. Exception { int count = 0; Input. Stream ins = new File. Input. Stream( filename ); Scanner scan = new Scanner( ins ); . . . } 18
Rule for Run. Time. Exceptions "If it is a Runtime. Exception, it is your fault!" -- Core Java, Volume 1, p. 560. You should be able to prevent Runtime exceptions by careful programming. How can you avoid these exceptions? n Null. Pointer. Exception n Array. Index. Out. Of. Bounds. Exception n Class. Cast. Exception often indicates faulty program logic. 19
Multiple Exceptions In C and Java a "try" block can catch multiple exceptions. q Exception handlers are tried in the order listed. q try { System. in. read(buf); parse. Line(buf); } catch (IOException e) { System. out. println("I/O exception "+e); } catch (Exception e) { System. out. println("Unknown exception "+e); } catch (Parse. Exception e( } /* This catch is never reached! */ System. out. println("Parse exception "+e); } 20
Nested Exception Handlers q You may also nest try - catch blocks. try { out = new File. Output. Stream("my file"); } catch(File. Not. Found. Exception e) { System. out. println("Error opening file"); throw e; } out. write(buf); } catch (IOException e) { System. out. println("I/O exception "+e); } catch (Exception e) { System. out. println("Unknown exception "+e); } 21
Propagation of Exceptions Exception are propagated according to the path of execution of a program. int test 1() { try { answer = B( ); } catch(Exception e) {. . . } } int test 2} () try} answer = B; ( ) {catch(Exception e( {. . . } { int A() {. . . throw new Exception("Help!"); } int B() {. . . int result = A( ); } 22
Propagation of Exceptions (2) An exception is propagated to the first enclosing scope that can "catch" the exception. int A(Object obj) { Integer k = (Integer)obj; // Class. Cast. Exception return k. Int. Value(); } /* B() only catches IOException */ int B(Object obj) { try { result = A(obj); } catch (IOException e) { /* do something */ } } /* C() catches any Runtime. Exception */ int C() { try { result = B("10"); } catch (Runtime. Exception e) {. . . } 23
Propagation of Exceptions (3) q q q If the application program does not provide an exception handler, then a default exception handler is used. In Java, the default exception handler: n prints name of exception and where it occurred n prints stack trace n terminates the program In C++, method terminate() is invoked n programmer can specify his own method using set_terminate( ) 24
Exceptions in C++ An exception can be any type! q Exceptions can be programmer defined or exceptions from the C++ standard library. q struct Error { } e; try { if ( n < 0 ) throw n; else if ( n == 0 ) throw "zero"; else if ( n == 1 ) throw e; } catch (int e 1) { cout << "integer exception raised" << endl; } catch (string e 2) { cout << "string exception " << endl; } catch (Error e 3( } cout << "struct Error" << endl{ ; 25
Exceptions in C++ Class Hierarchy include file exception <exception> bad_alloc <new> bad_cast <typeinfo> bad_exception <exception> bad_typeid <typeinfo> failure <ios> logic_error (has subclasses) <stdexcept> runtime_error (has subclasses) <stdexcept> q bad_exception is a generic type for unchecked exceptions. 26
Exception Handler in C++ q Example: catch failure of "new". #include <iostream> using namespace std; using std: : bad_alloc; char *make. Array(int nsize) { char *p; try { p = new char[nsize]; } catch ( bad_alloc e ) { cout << "Couldn't allocate array: "; cout << e. what( ) << endl; p = null; } 27
Declaring exceptions q To declare that your function throws an exception: #include <iostream> using namespace std; using std: : bad_alloc; char *make. Array(int nsize) throw(bad_alloc) { char *p; try { p = new char[nsize]; } catch ( bad_alloc e ) { cout << "Couldn't allocate array: "; cout << e. what( ) << endl; throw; // re-throw bad_alloc exception } 28
Declaring no exceptions q To declare that your function throws no exceptions: #include <iostream> using namespace std; using std: : bad_alloc; char *make. Array(int nsize) throw() { char *p; try { p = new char[nsize]; } catch ( bad_alloc e ) { cout << "Couldn't allocate array: "; cout << e. what( ) << endl; return NULL; } 29
Exception Handler in C++ q A function can have multiple "catch" blocks. int main( ) { try { sub(); /* sub() throws exceptions */ } catch ( bad_alloc e ) { cerr << "Allocation error " << e. what(); } catch ( exception e ) { cerr << "Exception " << e. what(); } catch (. . . ) { // ". . . " matches anything: this catch // block catches all other exceptions cerr << "Unknown exception " << endl; } 30
Rethrowing an Exception q A function can throw an exception it has caught: int main( ) { //. . . other code goes here. . . try { sub(); /* sub() that throws exceptions */ } catch ( bad_alloc e ) { cerr << "Allocation error " << e. what(); throw; } 31
C++ Default Exception Handler q If an exception is not caught, C++ provides a default exception handler: n n If the function didn't use "throw(something)" in its header, then a method named terminate() is called. If a function declares exceptions in its header, but throws some other exception, then the function unexpected() is called. unexpected() also calls terminate(). unexpected() in implemented as a pointer. You can change it to your own exception handler using: set_unexpected( your_function ) q Similarly, use set_terminate() to replace terminate() with some other function. q Prototypes for set_unexpected() and set_terminate() are defined in the header file <exception>. q 32
C++ Default Exception Handler #include <exception> void my_terminator() { cerr << "You're terminated!" << endl; exit(1); } void my_unexpected() { cout << "unexpected exception thrown" << endl; exit(1); } int main() throw() { set_unexpected(my_unexpected); // ignore return value set_terminate(my_terminator); for(int i = 1; i <=3; i++) try { f(i); } catch(some_exception e) { cout << "main: caught " << e. what() << endl; throw; } 33
Exception Handling is Expensive Actual student code to find a tree node matching string: class Node { String value; Node left, right; // branches of this node /** find a node that matches the string arg */ Node find( String arg ) { Node node; int compare = value. compare. To(arg ); if (compare == 0) return node; try { if (compare > 0) return left. find(arg ); if (compare < 0) return right. find(arg ); } catch ( Null. Pointer. Exception e ) { return null; } 34
Exception Handling is Expensive More efficient to write code that avoids exceptions: class Node { String value; Node left, right; // branches of this node /** find a node that matches the string arg */ Node find(String arg ) { Node node; int compare = value. compare. To( arg ); if (compare == 0) return node; if (compare > 0 && left != null) return left. find( arg ); else if (compare < 0 && right !== null) return right. find( arg ); else return null; } 35
Exception Questions q Do exception handlers use lexical or dynamic scope? q What is the purpose of "finally {. . . }" ? q What language introduced exception handling? q Efficiency: see homework problem. 36
Ordering of catch blocks try { } } } /* What is wrong with this code? */ y = func(x); catch ( exception ) { cerr << "caught exception"; catch ( bad_alloc ) { cerr << "caught bad_alloc"; catch (. . . ) { cerr << "what's this? "; catch ( logic_error ) { cerr << "Your Error!!"; try {/* What is wrong with this code? */ System. in. read(buf); /* throws IOException */ } catch ( Exception e ) { /* A */ System. err. println("Exception "+e); } catch ( IOException e ) { /* B */ System. err. println("IO exception "+e); } 37
Assertions are logical tests that should always be true at a given point in a program. q Programmers use assertions to help verify program correctness during development. q If an assertion is false, an exception is raised. q After the program is completed, assertions can be disabled using a compiler option, so they do not effect "production" code -- but are still available to the developer. q Both C++ and Java support assertions. q 38
Use of Assertions are used in methods to specify: Pre-conditions: conditions that should always be true when the method is invoked Post-conditions: conditions that should be true when the method returns class Node { String value; Node left, right; /** find a node that matches the string arg. * @precondition value is not null */ Node find(String what) { 39
Assertions Example Move discs from one stack to another stack in Towers of Hanoi game. Preconditions: q the "from" and "to" stacks are not null q the "from" stack must not be empty (has a disc) Postcondition: q the "to" stack contains at least one disc 40
Assertions Example void Move. Stack(Stack from. Stack, Stack to. Stack) { // stacks should not be null! assert from. Stack != null : "from stack is null"; assert to. Stack != null : "to stack is null"; // from. Stack should not be empty assert from. Stack. size() > 0 : "from stack empty"; . . . code goes here // Post. Condition: to. Stack not empty assert to. Stack. size() > 0 : "to stack is empty"; } 41
Enabling Assertions q You must enable assertions in order to activate them java -ea: [packagename. . . |classname. . . ] q This enables programmer to leave assertions in the source code (for development) without affecting users of the program. n q if not "enabled" (-ea), then the assert code is not run. in Java 1. 4 you must also use "-ea" with javac to compile assertion code. 42
"assert" versus "throw Assertion. Error" "assert" will throw an Assertion. Error. q You can use "assert". . . void push(Object obj) { // stack should not be null! assert stack != null : "Stack is null"; q or, throw an Assertion. Error. . . void push(Object obj) { // stack should not be null! if ( stack == null ) throw new Assertion. Error("Stack is null"); q Are these two equivalent? 43
"assert" in other languages q how to emulate assertions in C: /* myheader. h */ #define DEBUG 1 /* 0 for production version */ #include <myheader. h> #if DEBUG if ( from. Stack == null ) fprintf(stderr, "from. Stack is null"); #endif 44
- Slides: 44