06_Exceptions
Download
Report
Transcript 06_Exceptions
Exception Handling and Assertions
James Brucker
1
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" ?
2
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".
3
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.
4
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);
}
5
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);
}
6
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
7
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 =
}
sub B(
try
) {
new int[-1];
bad_alloc raised
) {
{
A( );
} catch( bad_cast ) {...}
}
sub C( ) {
try {
B( );
} catch( bad_alloc ) {...}
}
Scope exception handler
05-07 bad_cast 07
10-12 bad_alloc 10
8
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.
9
Exceptions in Java
Exceptions are objects from subclasses of "Throwable".
Throwable
Exception
RuntimeException
• IndexOutOfBounds
IOException
Error
others
Detected and
thrown by Java
• EOFException • ParseException VM, such as out• ZipException • user defined
of-heap space
• NullPointer
• ClassCast (bad cast) • many others
• 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 StupidUserException
extends RuntimeException {
public StupidUserException( 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
DataInputStream 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 wrong
err.println("I/O error: " + ioe);
} catch ( Exception e ) {
// processData( ) threw an exception
13
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
14
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()
15
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" !
16
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 lines
while( scan.hasNext() ) {
String line = scan.nextLine();
String [] words = line.split("\\s");
// "word" must start with a letter
for(int k=0; k<=words.length; k++)
if ( Character.isLetter( words[k].charAt(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 wordCount( String filename ) throws IOException,
NullPointerException,
IllegalStateException,
NoSuchElementException,
ArrayIndexOutOfBoundsException,
StringIndexOutOfBoundsException
{
int count = 0;
InputStream ins = new FileInputStream( filename );
Scanner scan = new Scanner( ins );
...
}
18
Rule for RunTimeExceptions
"If it is a RuntimeException, 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?
NullPointerException
ArrayIndexOutOfBoundsException
ClassCastException
ClassCastException often indicates faulty program
logic.
19
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); }
20
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); }
21
Propagation of Exceptions
Exception are propagated according to the path of
execution of a program.
int test1() {
try {
answer = B( );
} catch(Exception e)
{...}
}
int test2() {
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;// ClassCastException
return 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) { ... }
23
Propagation of Exceptions (3)
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( )
24
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; }
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>
bad_exception is a generic type for unchecked
exceptions.
26
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;
}
27
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
}
28
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;
}
29
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 exceptions
cerr << "Unknown exception " << endl;
}
30
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;
}
31
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>.
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.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;
}
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.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;
}
35
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.
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
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.
38
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) {
39
Assertions Example
Move 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
40
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 empty
assert fromStack.size() > 0 : "from stack empty";
... code goes here
// PostCondition: toStack not empty
assert toStack.size() > 0 : "to stack is empty";
}
41
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.
42
"assert" versus "throw AssertionError"
"assert" will throw an AssertionError.
You can use "assert" ...
void push(Object obj) {
// stack should not be null!
assert stack != null : "Stack is null";
or, throw an AssertionError ...
void push(Object obj) {
// stack should not be null!
if ( stack == null )
throw new AssertionError("Stack is null");
Are these two equivalent?
43
"assert" in other languages
how to emulate assertions in C:
/* myheader.h */
#define DEBUG 1
/* 0 for production version */
#include <myheader.h>
#if DEBUG
if ( fromStack == null )
fprintf(stderr, "fromStack is null");
#endif
44