Transcript chap09

10: Error Handling with Exceptions
•
•
•
•
•
•
•
•
•
•
Basic exceptions
– Exception arguments
Catching an exception
– The try block
– Exception handlers
Creating your own exceptions
The exception specification
– Catching any exception
– Rethrowing an exception
Standard Java exceptions
– The special case of RuntimeException
Performing cleanup with finally
– What’s finally for?
– Pitfall: the lost exception
Exception restrictions
Constructors
Exception matching
– Exception guidelines
Exercises
Basic exceptions
• Errors always occur in software programs. What really matters is:
– How is the error handled?
– Who handles it?
– Can the program recover, or just print error messages and
exit?
• The ideal time to catch an error is at compile-time, before you run
the program.
– However, not all errors can be detected at compile-time.
• In C and other earlier languages, you returned a special value or
set a flag, and the recipient was supposed to look at the value or
the flag to determine if something was wrong.
– However, as the years passed, it was discovered that programmers
who use a library tend to think of themselves as invincible.
• The Java programming language uses exceptions for error
handling.
int readFile {
initialize errorCode = 0;
open the file;
if (theFileIsOpen) {
determine the length of the file;
if (gotTheFileLength) {
allocate that much memory;
if (gotEnoughMemory) {
read the file into memory;
if (readFailed) {
errorCode = -1;
}
} else {
errorCode = -2;
}
} else {
errorCode = -3;
}
close the file;
if (theFileDidntClose && errorCode == 0) {
errorCode = -4;
} else {
errorCode = errorCode and -4;
} else {
errorCode = -5; }
return errorCode;
}
}
void readFile() {
try {
open the file;
determine its size;
allocate that much memory;
read the file into memory;
close the file;
} catch (fileOpenFailed) {
doSomething;
} catch (sizeDeterminationFailed) {
doSomething;
} catch (memoryAllocationFailed) {
doSomething;
} catch (readFailed) {
doSomething;
} catch (fileCloseFailed) {
doSomething;
}
}
//Processing flow is straight forward. //Error will not be neglected.
What's an Exception
• The term exception is shorthand for the phrase "exceptional
event."
– Definition: An exception is an event that occurs during the
execution of a program that disrupts the normal flow of
instructions.
• How to distinguish an exceptional condition from a normal
problem:
– Normal problem : when you have enough information in the
current context to somehow cope with the difficulty.
– Exceptional condition: you cannot continue processing
because you don’t have the information necessary to deal with
the problem in the current context.
– All you can do is jump out of the current context and relegate
that problem to a higher context. This is what happens when
you throw an exception .
• A simple example is a divide. If you’re about to divide by zero, it’s
worth checking to make sure you don’t go ahead and perform the
divide. But what does it mean that the denominator is zero?
Catching an exception
•
When does an exception occur?
– When you throw an exception
– Or another method you call throws an exception
•
If you’re inside a method and an exception occurs, that method will exit
in the process of throwing.
If you don’t want to exit the method, you can set up a special block to
capture the exception. This is called the try block.
•
CATCH
Catching an exception
try {
// Code that might generate exceptions
} catch(Type1 id1) {
// Handle exceptions of Type1
} catch(Type2 id2) {
// Handle exceptions of Type2
} catch(Type3 id3) {
// Handle exceptions of Type3
}
// etc...
• The handlers must appear directly after the try block.
• If an exception is thrown, the exception handling mechanism
goes hunting for the first handler that matches the type of the
exception.
– Then it enters that catch clause, and the exception is considered
handled.
– The search for handlers stops once the catch clause is finished.
public class Equalsmethod {
public static void main(String[] args){
double[] d=new double[10];
System.out.println(d[10]);
Double[] D=new Double[10];
System.out.println("Program continue..." );
}
}
C:\Java\jdk1.5.0>bin\java Equalsmethod
Exception in thread "main"
java.lang.ArrayIndexOutOfBoundsException: 10
at Equalsmethod.main(Equalsmethod.java:8)
Try{
xxxxx
xxxxx
if(…)throw xxx or calls a method in which
throws
xxxxx
xxxxx
}catch(…){
yyy
yyy
}
zzz
zzz
public class Equalsmethod{
public static void main(String[] args){
double[] d=new double[10];
try{
System.out.println(d[10]);
}catch(Exception e){
System.out.println("I caught it!");
}
Double[] D=new Double[10];
System.out.println("Program continue..." );
}
}
C:\Java\jdk1.5.0>bin\java Equalsmethod
I caught it!
Program continue...
Throw an Exception
• There are two constructors in all standard exceptions:
– the first is the default constructor,
– and the second takes a string argument so you can
place pertinent information in the exception:
if(t == null) throw new NullPointerException();
if(t == null) throw new NullPointerException("t = null");
Creating your own exceptions
class SimpleException extends Exception {}
public class SimpleExceptionDemo {
public void f() throws SimpleException {
System.out.println( "Throwing SimpleException from f()");
throw new SimpleException ();
}
public static void main(String[] args) {
SimpleExceptionDemo sed = new SimpleExceptionDemo();
try {
sed.f();
} catch(SimpleException e) {
System.err.println("Caught it!");
}
}
} ///:~
Throw SimpleException from f()
Caught it!
The exception specification
• In Java, you’re required to inform the client programmer, who
calls your method, of the exceptions that might be thrown from
your method.
• The exception specification uses an additional keyword, throws,
followed by a list of all the potential exception types.
void f() throws TooBig, TooSmall, DivZero {
//...
If you say
void f() {
// ...
• it means that no exceptions are thrown from the method.
– (Except for the exceptions of type RuntimeException,
– which can reasonably be thrown anywhere—this will be described
later.)
Catching any exception
•
•
By catching the base-class exception type
Exception, it is possible to create a
handler that catches any type of exception.
catch(Exception e) {
System.err.println("Caught an
exception");
}
This will catch any exception, you should
put it at the end of your list of handlers to
avoid preempting any exception handlers
that might otherwise follow it.
Methods of Exception
•
Methods of Exception (In fact come from its base type
Throwable )
String getMessage( )
-----detail message
String getLocalizedMessage( ) -----detail message
String toString( ) ------ short description + detail
message
void printStackTrace( )
void printStackTrace(PrintStream)
void printStackTrace(PrintWriter)
public class ExceptionMethods {
public static void main(String[] args) {
try {
throw new Exception(
"Here's my Exception");
} catch(Exception e) {
System.err.println("Caught Exception");
System.err.println( "e.getMessage(): " +
e.getMessage());
System.err.println(
"e.getLocalizedMessage(): " +
e.getLocalizedMessage());
System.err.println("e.toString(): " + e);
System.err.println("e.printStackTrace():");
e.printStackTrace(System.err);
}
}
} ///:~
Caught Exception
e.getMessage(): Here's my Exception
e.getLocalizedMessage(): Here's my
Exception
e.toString(): java.lang.Exception:
Here's my Exception
e.printStackTrace():
java.lang.Exception:
Here's my Exception
at
ExceptionMethods.main(Exception
Methods.java:7)
class TooBig extends Exception {}
class TooSmall extends Exception {}
class DivZero extends Exception {}
public class MyDivide {
double div(double a, double b) throws TooBig, TooSmall, DivZero {
double ret;
if ( b==0.0) throw new DivZero();
ret = a/b;
if(ret < 0.001) throw new TooSmall ();
if(ret >1000) throw new TooBig ();
return ret;
}
} ///:~
Standard Java exceptions
•
The Java class Throwable describes anything that can be
thrown as an exception.
The special case of RuntimeException
ArithmeticException, ClassCastException,
llegalArgumentException, IllegalStateException,
IndexOutOfBoundsException, NoSuchElementException,
NullPointerException,
1) Java will automatically throw a NullPointerException.
if(t == null) throw new NullPointerException();
else t.somefunc();
the above bit of code equals to:
t.somefunc();
The special case of RuntimeException
2)You never need to write an exception specification saying that a
method might throw a RuntimeException, since that’s just
assumed. Because they indicate bugs, you virtually never catch
a RuntimeException
3)Since the compiler doesn’t enforce exception specifications for
these, it’s quite plausible that a RuntimeException could
percolate all the way out to your main( ) method without
being caught.
The special case of RuntimeException
public class NeverCaught {
static void f() { throw new RuntimeException("From f()"); }
static void g() { f(); }
public static void main(String[] args) { g(); }
} ///:~
The output is:
Exception in thread "main"
java.lang.RuntimeException: From f()
at NeverCaught.f(NeverCaught.java:9)
at NeverCaught.g(NeverCaught.java:12)
at NeverCaught.main(NeverCaught.java:15)
So the answer is: If a RuntimeException gets all the way out to
main( ) without being caught, printStackTrace( ) is called for
that exception as the program exits.
Performing cleanup with finally
There’s often some piece of code that you want to execute whether
or not an exception is thrown within a try block.
try {
// The guarded region: Dangerous activities
// that might throw A, B, or C
} catch(A a1) {
// Handler for situation A
} catch(B b1) {
// Handler for situation B
} catch(C c1) {
// Handler for situation C
} finally {
// Activities that happen every time
}
Try{
xxxxx
xxxxx
if(…)throw xxx or calls a method in which
throws
xxxxx
xxxxx
}catch(…){
yyy
yyy
}finally{
zzz
zzz
}
Performing cleanup with finally
class ThreeException extends Exception {} ThreeException
public class FinallyWorks {
In finally clause
static int count = 0;
public static void main(String[] args) { No exception
In finally clause
while(true) {
try {
// Post-increment is zero first time:
if(count++ == 0) throw new ThreeException();
System.out.println("No exception");
} catch(ThreeException e) {
System.err.println("ThreeException");
} finally {
System.err.println("In finally clause");
if(count == 2) break; // out of "while"
}
} } } ///:~
Exception restrictions
•
When you override a method, you can throw only
the exceptions that have been specified in the baseclass version of the method.
–
•
•
This is a useful restriction, since it means that code that
works with the base class will automatically work with any
object derived from the base class, including exceptions.
The exception specifications are not part of the type
of a method, Therefore, you cannot overload
methods based on exception specifications.
An exception specification exists in a base-class
version of a method doesn’t mean that it must exist
in the derived-class version of the method.
–
this is precisely the opposite of the rule for the class
interface during inheritance.
Exception restrictions
•
The restriction on exceptions does not apply to
constructors.
–
•
The constructor of a subclass can throw anything it wants,
regardless of what the base-class constructor throws.
Note that a derived-class constructor cannot catch
exceptions thrown by its base-class constructor.
–
Since a base-class constructor must always be called one
way or another, the derived-class constructor must declare
any base-class constructor exceptions in its exception
specification.
class BaseballException extends Exception {}
class Foul extends BaseballException {}
class Strike extends BaseballException {}
abstract class Inning {
Inning() throws BaseballException {}
void event () throws BaseballException {
// Doesn't actually have to throw
anything
}
abstract void atBat() throws Strike, Foul;
void walk() {} // Throws nothing
}
class StormException extends Exception {}
class RainedOut extends StormException {}
class PopFoul extends Foul {}
interface Storm {
void event() throws RainedOut;
void rainHard() throws RainedOut;
}
class BaseballException extends Exception {}
class Foul extends BaseballException {}
class Strike extends BaseballException {}
abstract class Inning {
Inning() throws BaseballException {}
void event () throws BaseballException {
// Doesn't actually have to throw
anything }
abstract void atBat() throws Strike, Foul;
void walk() {} // Throws nothing
}
class StormException extends Exception {}
class RainedOut extends StormException {}
class PopFoul extends Foul {}
interface Storm {
void event() throws RainedOut;
void rainHard() throws RainedOut;
}
public class StormyInning extends Inning
implements Storm {
// OK to add new exceptions for
// constructors, but you must deal
// with the base constructor exceptions:
StormyInning() throws RainedOut,
BaseballException {}
StormyInning(String s) throws Foul,
BaseballException {}
// Regular methods must conform to base class:
//Compile error
//! void walk() throws PopFoul {}
// Interface CANNOT add exceptions to existing
// methods from the base class:
//void event () throws BaseballException {}
//! public void event() throws RainedOut {}
// If the method doesn't already exist in the
// base class, the exception is OK:
public void rainHard() throws RainedOut {}
// You can choose to not throw any exceptions,
// even if base version does:
public void event() {}
// Overridden methods can throw
// inherited exceptions:
void atBat() throws PopFoul {}
public static void main(String[] args) {
try {
StormyInning si = new
StormyInning();
si.atBat();
} catch(PopFoul e) {
System.err.println("Pop foul");
} catch(RainedOut e) {
System.err.println("Rained out");
} catch(BaseballException e) {
System.err.println("Generic
error");
}
// Strike not thrown in derived version.
try { // What happens if you upcast?
Inning i = new StormyInning();
i.atBat();
// You must catch the exceptions from the
// base-class version of the method:
} catch(Strike e) {
System.err.println("Strike");
} catch(Foul e) {
System.err.println("Foul");
} catch(RainedOut e) {
System.err.println("Rained out");
} catch(BaseballException e) {
System.err.println( "Generic
baseball exception");
}
} } ///:~
Exception matching(1)
class Annoyance extends Exception {}
class Sneeze extends Annoyance {}
public class Human {
public static void main(String[] args) {
try {
if(…) throw new Sneeze();
else throw new Annoyance ();
} catch(Sneeze s) {
System.err.println("Caught Sneeze");
} catch(Annoyance a) {
System.err.println("Caught Annoyance");
}
}
} ///:~
Exception matching(2)
class Annoyance extends Exception {}
class Sneeze extends Annoyance {}
public class Human {
public static void main(String[] args) {
try {
if(…) throw new Sneeze();
else throw new Annoyance ();
} catch(Annoyance a) {
System.err.println("Caught Annoyance");
} catch(Sneeze s) {
System.err.println("Caught Sneeze");
}
}
} ///:~
Exercises
6. Create three new types of exceptions. Write a class
with a method that throws all three(using method
Math.random()*3 and switch statement ). In
main( ), call the method but only use a single
catch clause that will catch all three types of
exceptions.
8. Write code (without throw statement) to generate different
RuntimeExceptions including ArrayIndexOutOfBoundsException,
NullPointerException, ClassCastException etc., and only catch
some of them, adding a finally block to show that the code in
finally block will be executed even exception is not caught.