1 Exception Handling and Assertions James Brucker.

44
1 Exception Handling and Assertions James Brucker

Transcript of 1 Exception Handling and Assertions James Brucker.

1

Exception Handling and Assertions

James Brucker

2

Exceptions

Exceptions are unusual events detected by the computer or software.

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

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" ?

3

Types of Exceptions

Hardware Errors such as write to write-protected devices.

hardware failures are usually fatal handled by hardware or OS, not application program.

Software Errors including access to invalid memory address, attempt to access non-existent file.

Language Violations (dynamic semantic errors): illegal array subscript, referencing null pointers.

User-defined (program-defined) conditions e.g., a ParseException thrown in a recursive-descent program. Java and C++ allow user to define and raise any "exception".

4

What triggers exceptions?

Hardware: hardware may prevent writing to some devices (read-only) restrict access to memory

OS or Executor: Java VM detects null reference, I/O, and array bounds errors OS enforces file permissions Java Security Manager (raises SecurityException)

User program: 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.

5

Exception Handler

try {

block-of-code;

}

catch (ExceptionType1 e) { handler-code; }

catch (ExceptionType2 e) { handler-code; } ...

finally { code to always execute before continuing; }

Stringbuffer buffer = new StringBuffer();try {

while ( ( c = System.in.read() ) != 0 )buffer.append(c);

} catch (IOException e) {System.out.println("I/O error: " + e);

}

6

Exception Handler (2)

An exception handler is statically (lexically) bound to a block of code.

Unlike "lexically scoped" variables, the scope of an exception includes any function calls inside its block:

try {String line = bufferedReader.readLine( );writer( line );

}catch ( IOException e ) {

System.out.println("I/O error: "+e); }

7

Two Exception Handling Modes

resumption: after the exception handler runs, the program continues at the point where the exception occurred.

termination: flow of execution branches to exception handler and does not return to the point of exception.

try {

p = read( fHandle );

process(p);

}

catch ( exception ) {

...

}

doSomethingElse( );

Exception raised

resumption

termination

8

Exception Propagation

Exception handlers form a stack, each with a scope. When an exception occurs, the run-time must find an

exception handler on the handler stack it must "unwind" the call stack during the search.

sub A( ) {p = new int[-1];

}sub B( ) {

try {A( );

} catch( bad_cast ) {...}}sub C( ) {

try {B( );

} catch( bad_alloc ) {...}}

bad_alloc raised

Scope exception handler

05-07 bad_cast 07

10-12 bad_alloc 10

9

Exception Handling is Expensive

Runtime environment must locate first handler. Unwind call chain and stack

locate return address of each stack frame and jump to it.

invoke "epilogue" (return) code for each function branch to the exception handler

Recommendation: avoid exceptions in normal flow of execution.

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.

10

Exceptions in Java

Exceptions are objects from subclasses of "Throwable".

Throwable

Error Exception

IOExceptionRuntimeException others Detected and thrown by Java VM, such as out-of-heap space

• IndexOutOfBounds• NullPointer• ClassCast (bad cast)• many others (see API)

• EOFException• ZipException• many others

• ParseException

• user defined• many others

11

Exceptions in C++

A C++ program can throw anything.

Standard exception classes:

exception

runtime_error logic_error

bad_alloc

bad_typeid

bad_cast range_error

overflow_error

underflow_error

length_error

domain_error out_of_range invalid_argument

bad_exception

ios_base::failure

12

Why Use an Exception Hierarchy?

1. Makes exception collection extensible.

/** Define an exception for stupid users */

public class StupidUserException extends RuntimeException {

public StupidUserException( String msg ) {super( msg );

}

}

13

Why Use an Exception Hierarchy?

2. Programmer can write multiple "catch" blocks arranged hierarchically.

// read binary data from a fileDataInputStream din = new DataInputStream( ... );try {

count = din.read( bytearray );processData( bytearray );

} catch ( EOFException eof ) {// no problem ... just close file and continue

} catch ( IOException ioe ) {// oops... something wrongerr.println("I/O error: " + ioe);

} catch ( Exception e ) {// processData( ) threw an exception

14

Two Types of Exceptions in Java

Two categories of exceptions: Checked Exceptions are exceptions that Java requires

the program to either handle or explicitly acknowledge that it may generate this exception.

Example:

readData(String filename) throws ...what?

Unchecked Exceptions: the program may provide an exception handler (try ... catch) but is not required.

Unchecked Exceptions are for events that the programmer can avoid by careful programming.

would be tedious to require acknowledging all of them

15

Checked Exceptions in Java Checked Exceptions include subclasses of

IOException CloneNotSupportedException user-defined classes that extend Exception.

Programmer declares that a method "throws" an exception to a higher-level handler by writing:

methodname(params) throws SomeException

readData(String filename) throws IOException {

try {

URL myurl = new URL("http://www.ku.ac.th");

} catch (MalformedURLException expt) { ... }

// other IOException is thrown by readData()

16

Unchecked Exceptions in Java

Unchecked Exceptions: the program may provide an exception handler (try ... catch) but is not required.

Unchecked Exceptions include subclasses of Error and RunTimeException.

Methods should not use "... throws SomeException" for Unchecked Exceptions.

Reason: Error conditions are beyond the control of the application.

You should let the JavaVM handle them, or It would be too cumbersome to require every program to

either "catch" or "throw" all RunTimeExceptions. For example, every object reference would require declaring or

catching "NullPointerException" !

17

Exceptions Example

What exceptions may this Java code throw?/* count the words in a file */int wordCount( String filename ) {

int count = 0;InputStream ins = new FileInputStream( filename );Scanner scan = new Scanner( ins );// read input lineswhile( scan.hasNext() ) {

String line = scan.nextLine();String [] words = line.split("\\s");// "word" must start with a letterfor(int k=0; k<=words.length; k++)if ( Character.isLetter( words[k].charAt(0) ) )

count++;}return count;

}

18

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 wordCount( String filename ) throws IOException,

NullPointerException, IllegalStateException, NoSuchElementException, ArrayIndexOutOfBoundsException, StringIndexOutOfBoundsException

{int count = 0;InputStream ins = new FileInputStream( filename );Scanner scan = new Scanner( ins );...

}

19

Rule for RunTimeExceptions

You should be able to prevent Runtime exceptions by careful programming.

How can you avoid these exceptions? NullPointerException ArrayIndexOutOfBoundsException ClassCastException

ClassCastException often indicates faulty program logic.

"If it is a RuntimeException, it is your fault!"

-- Core Java, Volume 1, p. 560.

20

Multiple Exceptions

In C and Java a "try" block can catch multiple exceptions.

Exception handlers are tried in the order listed.try {

System.in.read(buf);parseLine(buf);

} catch (IOException e) { System.out.println("I/O exception "+e); }catch (Exception e) { System.out.println("Unknown exception "+e); }catch (ParseException e) { /* This catch is never reached! */ System.out.println("Parse exception "+e); }

21

Nested Exception Handlers

You may also nest try - catch blocks.

try {try { out = new FileOutputStream("my file");} catch(FileNotFoundException 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); }

22

Propagation of Exceptions

Exception are propagated according to the path of execution of a program.

int A() {...throw new Exception("Help!");

}int B() {

...int result = A( );

}

int test1() {try {

answer = B( );} catch(Exception e) {...}

}int test2() {

try {answer = B( );

} catch(Exception e) {...}

}

23

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;// ClassCastExceptionreturn k.IntValue();

}/* B() only catches IOException */int B(Object obj) {

try {result = A(obj);

} catch (IOException e) { /* do something */ }}/* C() catches any RuntimeException */int C() {

try {result = B("10");

} catch (RuntimeException e) { ... }

24

If the application program does not provide an exception handler, then a default exception handler is used.

In Java, the default exception handler: prints name of exception and where it occurred prints stack trace terminates the program

In C++, method terminate() is invoked programmer can specify his own method using set_terminate( )

Propagation of Exceptions (3)

25

Exceptions in C++ An exception can be any type! Exceptions can be programmer defined or exceptions

from the C++ standard library.

struct Error { } e;try {

if ( n < 0 ) throw n;else if ( n == 0 ) throw "zero";else if ( n == 1 ) throw e;

} catch (int e1) { cout << "integer exception raised" << endl; }catch (string e2) { cout << "string exception " << endl; }catch (Error e3) { cout << "struct Error" << endl; }

26

Exceptions in C++

Class Hierarchy include fileexception <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>

bad_exception is a generic type for unchecked exceptions.

27

Exception Handler in C++

Example: catch failure of "new".

#include <iostream>using namespace std;using std::bad_alloc;char *makeArray(int nsize) {

char *p;try {

p = new char[nsize];} catch ( bad_alloc e ) {

cout << "Couldn't allocate array: ";cout << e.what( ) << endl;p = null;

}

28

Declaring exceptions

To declare that your function throws an exception:

#include <iostream>using namespace std;using std::bad_alloc;char *makeArray(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

}

29

Declaring no exceptions

To declare that your function throws no exceptions:

#include <iostream>using namespace std;using std::bad_alloc;char *makeArray(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;

}

30

Exception Handler in C++

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 exceptionscerr << "Unknown exception " << endl;

}

31

Rethrowing an Exception

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;

}

32

C++ Default Exception Handler

If an exception is not caught, C++ provides a default exception handler:

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 )

Similarly, use set_terminate() to replace terminate() with some other function.

Prototypes for set_unexpected() and set_terminate() are defined in the header file <exception>.

33

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;}

34

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.compareTo(arg );if (compare == 0) return node;try {

if (compare > 0) return left.find(arg );if (compare < 0) return right.find(arg );

} catch ( NullPointerException e ) {return null;

}

35

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.compareTo( 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;

}

36

Exception Questions

Do exception handlers use lexical or dynamic scope?

What is the purpose of "finally { ... }" ?

What language introduced exception handling?

Efficiency: see homework problem.

37

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);}

38

Assertions

Assertions are logical tests that should always be true at a given point in a program.

Programmers use assertions to help verify program correctness during development.

If an assertion is false, an exception is raised. 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.

Both C++ and Java support assertions.

39

Use of Assertions

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) {

40

Assertions ExampleMove discs from one stack to another stack in Towers of Hanoi game.

Preconditions: the "from" and "to" stacks are not null the "from" stack must not be empty (has a disc)

Postcondition: the "to" stack contains at least one disc

41

Assertions Example

void MoveStack(Stack fromStack, Stack toStack){

// stacks should not be null!assert fromStack != null : "from stack is null";assert toStack != null : "to stack is null";// fromStack should not be emptyassert fromStack.size() > 0 : "from stack empty";

... code goes here

// PostCondition: toStack not emptyassert toStack.size() > 0 : "to stack is empty";

}

42

Enabling Assertions You must enable assertions in order to activate them

java -ea

java -ea:[packagename...|classname...]

This enables programmer to leave assertions in the source code (for development) without affecting users of the program.

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.

43

"assert" versus "throw AssertionError"

"assert" will throw an AssertionError. You can use "assert" ...

or, throw an AssertionError ...

Are these two equivalent?

void push(Object obj) {// stack should not be null!assert stack != null : "Stack is null";

void push(Object obj) {// stack should not be null!if ( stack == null )throw new AssertionError("Stack is null");

44

"assert" in other languages

how to emulate assertions in C:

#include <myheader.h>

#if DEBUGif ( fromStack == null )fprintf(stderr, "fromStack is null");

#endif

/* myheader.h */

#define DEBUG 1 /* 0 for production version */