Exceptions and Exception Handling

advertisement
Exceptions and Exception Handling
Errors
all programs encounter error conditions:
incorrect use of methods: incorrect or invalid parameter values (e.g.
divide by zero, null pointers)
resource exhaustion: out of memory, disk space, OS resources...
external systems: 3rd party libraries, hardware interfaces...
implementation limits: numerical limits, data structure size limits...
programs must be robust, that is they must behave
reasonably in the presence of errors
ideally, programs exhibit graceful degradation, where they
continue to function approximately as they would in the
absence of errors.
Unexceptional approaches
many ways to handle errors
special return values
not an option if the range of the function covers all possible values
inconvenient: almost every statement is accompanied by an
if..then..else, and must provide a variable to store the value
inconsistent method semantics
global error code, e.g. lastError
can be difficult to understand and debug
global variables are easy to corrupt
error code parameter
requires extra space on the call stack
can be cumbersome to use
requires pass-by-reference
The Exception Philosophy
a method can terminate one of two ways: exceptionally or
normally.
a client programmer cannot ignore when a method
terminates exceptionally
when an exceptional circumstance arises in a method, it
stops, and throws an exception.
the caller can then catch the exception, and deal with it.
A typical example
In Java, arrays are objects. Thus they can throw
exceptions, and they do!
If you try to access the array at an invalid index
(e.g. i < 0 || i > length ), the array will throw an exception.
public class ExceptionExample {
public static void main( String args[] ) {
int someInts[] = new int[3];
for ( int i = 0;; i++ )
{
try {
someInts[i] = i;
}
catch ( IndexOutOfBoundsException e ) {
// uh-oh! we went past the end of the array
break;
}
} // end for
} // end main
}
What is an exception?
an exception is an object in Java, which hold information
about the exceptional event
all exceptions are subclasses of java.lang.Throwable
three methods of general
interest:
String constructor, sets
the explanation string
toString() returns a
string that explains the
exceptional event
printStackTrace()
prints the call stack from
when the exception occured
(helpful in debugging)
Checked and unchecked exceptions
there are two types of exceptions in Java, checked and
unchecked
checked
derived from java.lang.Exception
methods must declare (at compile time) if they throw checked
exceptions
caller must handle all checked exceptions
unchecked
derived from java.lang.RuntimeException
does not have to be handled by the caller
Example of checked and unchecked exceptions
public class CheckVsUnchecked {
public void someMethod( InputStream in ) {
// MUST put call to read() in a try block, or else compile error.
// This is because IOException is a CHECKED exception
try {
in.read();
}
catch ( IOException e ) {
// caught it!
}
int fiveInts[] = new int[5];
// don't have to put this in a try block, because IndexOutOfBounds
// is an UNCHECKED exception. We could still try-catch it though.
fiveInts[6] = 100;
}
}
How to throw an exception
throwing an exception involves :
determine the exceptional circumstance
create an exception object of the desired type, and include the
explanation message in the constructor
throw the exception!
if the exception is checked (most user defined exceptions
are), you must also include in the method declaration the
types of exceptions that can be thrown
Throwing an exception: example
public void anotherMethod() throws IOException {
BarcodeReader reader = new BarcodeReader();
int checksum = reader.getCheckSum();
int calculatedChecksum = calculateCheckSum( reader.getCode() );
if ( checksum != calculatedChecksum ) {
throw new IOException( “bad barcode, checksums don't match” );
}
}
How to catch an exception, and what to do with it once
you've caught it
catch exceptions using try-catch blocks.
try-block wraps the method calls that may throw exceptions
catch block(s) specify what to do depending on the type of the exception
reflecting exceptions
if your method catches an exception, it may throw another exception
appropriate if your method can't fix (or safely ignore) the problem
happens automatically if you don't use catch()
masking exceptions
when your method catches an exception, it can deal with the problem (or
maybe ignore it, if we know that it is safe to do so), and not throw any more
exceptions
e.g. can use array-bounds checking instead of checking the loop counter*,
and just continue normal processing after the catch-block
* depending on how exception handling is implemented, this may be an
expensive way to iterate through an array, or a very cheap way.
Handling exceptions example
public void exceptionalMethod( InputStream in ) throws IOException {
int someInts[] = new int[5];
try {
int x = in.read(); // can throw IOExceptions
someInts[x] = x;
// can throw ArrayIndexOutOfBoundsExceptions
x = x / 0;
// can throw ArithmeticExceptions
}
catch ( IndexOutOfBoundsException e ) {
// reflect IndexOutOfBoundsExceptions as IOExceptions, for the
// sake of the example (better to define a new exception type)
throw new IOException( “Not really an IO problem: “ + e );
}
catch ( ArithmeticException e ) {
// mask divide-by-zero exceptions by just reporting them
System.err.println( e );
}
// implied reflection of IOExceptions from read(), because they
// are uncaught
}
Be careful handling exceptions
remember that a catch-block will handle any exception of
the type declared.
in this example, the code will erroneously assume that the
search problem is fixed, which will not be true because the
catch-block only fixes problems with y
try {
x = y[n];
i = Arrays.search( z, x );
}
catch ( IndexOutOfBOundsException e ) {
// deal with accessing y out of bounds
}
// here we assume all is well, but the catch won't fix problems
// related to the search call.
Finally
after all of the catch-blocks, you can add a finally-block
the finally block will always be executed, whether or not an
exception occurs.
usually this is used for clean-up and restore operations,
such as releasing file handles or refreshing the screen.
BEWARE: if an exception occurs inside a finally-block, it will
clobber any other exceptions that have occured. This can
cause you to lose exceptions.
Defining your own exceptions
decide if your exception should be checked or unchecked
sub-class Exception or RuntimeException
(respectively)
override constructors:
public class MyNewException extends Exception {
public MyNewException() { super(); }
public MyNewException( String s ) { super( s ); }
}
you can be more clever, and add other helpful constructors, usually
that result in a call like super( someCleverMessage );
it is good style to name your exception
<error_name>Exception
When to use exceptions, and when not to
exceptions should be used to eliminate complicated rules
about what is valid input to a method
another good use is to avoid returning “special values” to
indicate errors from a method
remember that exception handling can be expensive, so
don't use them for local results, like when a search-loop
finishes without finding a match
Summary of exceptions in Java
handle exceptions using:
throw exceptions by:
declaring types of exceptions to be thrown
e.g. public int myMethod() throws IOException {
try {
...
}
catch ( Exception e ) {
// can refer to e in this block
...
}
finally {
...
}
creating and throwing instances of the exceptions
e.g. throw new IOException( “error details” );
Download