Exceptions in Java - lily Development Group

Download Report

Transcript Exceptions in Java - lily Development Group

Exceptions in Java
Christian Ratliff
<[email protected]>
Sr. Technology Architect
Core Libraries Group
DeLorme Mapping
Presentation Sections
1. A lexicon and short history of exceptions.
2. Working with exceptions in Java.
3. Designing an effective exception class hierarchy.
4. Advanced exception handling.
Copyright (c) 2001 DeLorme
2
Section One
A lexicon and short history of exceptions.
Lexicon: Actors and Actions
Operation
A method which can possibly raise an exception.
Invoker
A method which calls operations and handles resulting exceptions.
Exception
A concise, complete description of an abnormal event.
Raise
Brings an exception from the operation to the invoker, called throw in
Java. Another very common word for this is emit.
Handle
Invoker’s response to the exception, called catch in Java.
Backtrack
Ability to unwind the stack frames from where the exception was raised to
the first matching handler in the call stack.
Copyright (c) 2001 DeLorme
4
Lexicon: Types of Exceptions
Hardware
Generated by the CPU in response to a fault (e.g. divide by zero, overflow,
segmentation fault, alignment error, etc).
Software
Defined by the developer to represent any other type of failure. These
exceptions often carry much semantic information.
Domain Failure
The inputs, or parameters, to the operation are considered invalid or
inappropriate for the requested operation.
Range Failure
Operation cannot continue, or output is possibly incorrect.
Monitor
Describes the status of an operation in progress, this is a mechanism for
runtime updates which is simpler than subthreads.
Copyright (c) 2001 DeLorme
5
Error Handling Before Exceptions
Error handling, before exceptions, took one of two forms:
Parameterized forms:



Address of a subroutine to be called during an error.
Name of a statement labels to jump to on error.
Status variables changed by the operation, and then checked by
invoker at operation return.
Language-based forms:



Fault subroutines tied to a type or instance.
Fault target defined at compile time on the subroutine.
PL/I condition statements.
Copyright (c) 2001 DeLorme
6
Problems with these Systems
Parameterized Calls



Language Forms
Not required to handle
exceptional results
No way to detect at compile
time whether the exception is
handled.
Limited number of conditionhandler pairings.



One handler per exception
per type or object.
Handler for each subroutine
is predefined.
PL/I solution was not given to
general use.
How do we resolve these problems, and move from a system where
error handling is both inconsistent and ignorable to something
logically structured?
Copyright (c) 2001 DeLorme
7
Birth of Modern Exceptions
C.A.R. Hoare devised an exception processing system like:
Q1 otherwise Q2
John B. Goodenough described exceptions as:






Hierarchical
Classified
Backtracking
Explicitly Declared
Resumable
Defaultable
Copyright (c) 2001 DeLorme
8
Goodenough’s Notation
/* Declare an operation G, which can raise an exception X */
DECL G ENTRY (FIXED) [X:…];
/* Call G with parameter A and handle possible exceptions */
CALL G(A); [X: handler-action]
/* Handle an exception if A added to B overflows C */
C = (A + B); [OVERFLOW: handler-action]
/* Handle two possible overflow exceptions separately */
C = (A * (B * B) [OVERFLOW: handler-action1]); [OVERFLOW: handler-action2]
/* Handle exceptions from any element of the loop */
DO WHILE (…)
CALL G(A);
C = (A + B);
END; [X: …, OVERFLOW: …]
/* Handle an exception from any member of a statement group */
DO
CALL G(A);
C = (A + B);
END; [X: …, OVERFLOW: …]
Copyright (c) 2001 DeLorme
9
Advantages of this Notation
Enables transfer of control from location of the fault, to code which
knows how to handle that particular fault.
Exceptions cannot be ignored, they must be caught or the
application will terminate.
Separates the error management from the normal code.
Simplifies error processing by allowing entire blocks to be
combined inside one exception handler.
Exceptions are divided into three major groups:



ESCAPE requires termination of the operation in progress.
NOTIFY explicitly forbids termination of the operation, this is a
monitor.
SIGNAL allows the invoker to either terminate or resume the operation
in progress.
Copyright (c) 2001 DeLorme
10
Questions for Section One
?
Copyright (c) 2001 DeLorme
11
Section Two
Working with exceptions in Java
Classifying Java Exceptions
Unchecked Exceptions
It is not required that these types
of exceptions be caught or
declared on a method.



Runtime exceptions can be
generated by methods or by the
JVM itself.
Errors are generated from deep
within the JVM, and often
indicate a truly fatal state.
Runtime exceptions are a source
of major controversy!
Checked Exceptions
Must either be caught by a
method or declared in its
signature.



Placing exceptions in the method
signature harkens back to a
major concern for Goodenough.
This requirement is viewed with
derision in the hardcore C++
community.
A common technique for
simplifying checked exceptions is
subsumption.
Copyright (c) 2001 DeLorme
13
Keywords for Java Exceptions
throws
Describes the exceptions which can be raised by a method.
throw
Raises an exception to the first available handler in the call stack,
unwinding the stack along the way.
try
Marks the start of a block associated with a set of exception handlers.
catch
If the block enclosed by the try generates an exception of this type,
control moves here; watch out for implicit subsumption.
finally
Always called when the try block concludes, and after any necessary catch
handler is complete.
Copyright (c) 2001 DeLorme
14
General Syntax
public void setProperty(String p_strValue) throws NullPointerException
{
if (p_strValue == null) { throw new NullPointerException(“...”); }
}
public void myMethod() {
MyClass oClass = new MyClass();
try {
oClass.setProperty(“foo”);
oClass.doSomeWork();
} catch (NullPointerException npe) {
System.err.println(“Unable to set property: “+npe.toString());
} finally {
oClass.cleanup();
}
}
Copyright (c) 2001 DeLorme
15
Canonical Example
public void foo() {
try { /* marks the start of a try-catch block */
int a[] = new int[2];
a[4] = 1; /* causes a runtime exception due to the index */
} catch (ArrayIndexOutOfBoundsException e) {
System.out.println("exception: " + e.getMessage());
e.printStackTrace();
}
}
/* This code also compiles, but throws an exception at runtime! It
* is both less obvious and more common (an off-by-one-error). */
public int[] bar() {
int a[] = new int[2];
for (int x = 0; x <= 2; x++) { a[x] = 0; }
return a;
}
Copyright (c) 2001 DeLorme
16
throw(s) Keyword
/* The IllegalArgumentException is considered unchecked, and
* even making it part of the signature will not alter that. */
public void setName(String p_strName) throws IllegalArgumentException
{
/* valid names cannot be zero length */
if (p_strName.length() == 0) {
throw new IllegalArgumentException(“…”);
}
m_strName = p_strName;
}
public void foo() {
setName(“”); /* No warning about unhandled exceptions. */
}
Copyright (c) 2001 DeLorme
17
throw(s) Keyword, part 2
/* Make a bad parameter exception class */
class NuttyParameterException extends Exception { … }
/* To really make an invoker pay attention, use a checked
* exception type rather than a Runtime Exception type, but
* you must declare that you will throw the type! */
public void setName(String p_strName) /* error here! */
{
/* valid names cannot be zero length */
if (p_strName == null || p_strName.length() == 0) {
throw new NuttyParameterException(“…”);
}
m_strName = p_strName;
}
Copyright (c) 2001 DeLorme
18
throw(s) Keyword, part 3
/* Make a bad parameter exception class */
class NuttyParameterException extends Exception { … }
/* To really make an invoker pay attention, use a checked
* exception type rather than a Runtime Exception type. */
public void setName(String p_strName) throws NuttyParameterException
{
/* valid names cannot be zero length */
if (p_strName == null || p_strName.length() == 0) {
throw new NuttyParameterException(“…”);
}
m_strName = p_strName;
}
/* Many of us will have an unquenchable desire to use a Runtime
* exception in the above, but resist! */
public void foo() {
setName(“”); /* This does result in an error. */
}
Copyright (c) 2001 DeLorme
19
try Keyword
/* The try statement marks the position of the first bytecode instruction
* protected by an exception handler. */
try {
UserRecord oUser = new UserRecord();
oUser.setName(“Fred Stevens”);
oUser.store();
/* This catch statement then marks the final bytecode instruction
* protected, and begins the list of exceptions handled. This info
* is collected and is stored in the exception table for the method. */
} catch (CreateException ce) {
System.err.println(“Unable to create user record in the database.”);
}
Copyright (c) 2001 DeLorme
20
catch Keyword
/* A simple use of a catch block is to catch the exception raised by
* the code from a prior slide. */
try {
myObject.setName(“foo”);
} catch (NuttyParameterException npe) {
System.err.println(“Unable to assign name: “ + npe.toString());
}
try { /* example 2 */
myObject.setName(“foo”);
} catch (NuttyParameterException npe) { /* log and relay this problem. */
System.err.println(“Unable to assign name: “ + npe.toString());
throw npe;
}
Copyright (c) 2001 DeLorme
21
catch Keyword, part 2
/* Several catch blocks of differing types can be concatenated. */
try {
URL myURL = new URL("http://www.mainejug.org");
InputStream oStream = myURL.openStream();
byte[] myBuffer = new byte[512];
int nCount = 0;
while ((nCount = oStream.read(myBuffer)) != -1) {
System.out.println(new String(myBuffer, 0, nCount));
}
oStream.close();
} catch (MalformedURLException mue) {
System.err.println("MUE: " + mue.toString());
} catch (IOException ioe) {
System.err.println("IOE: " + ioe.toString());
}
Copyright (c) 2001 DeLorme
22
finally Keyword
URL myURL = null;
InputStream oStream = null;
/* The prior sample completely neglected to discard the network
* resources, remember that the GC is non-determinstic!! */
try {
/* Imagine you can see the code from the last slide here... */
} finally { /* What two things can cause a finally block to be missed? */
/* Since we cannot know when the exception occurred, be careful! */
try {
oStream.close();
} catch (Exception e) {
}
}
Copyright (c) 2001 DeLorme
23
finally Keyword, part 2
public bool anotherMethod(Object myParameter) {
try { /* What value does this snippet return? */
myClass.myMethod(myParameter);
return true;
} catch (Exception e) {
System.err.println(“Exception in anotherMethod() “+e.toString());
return false;
} finally {
/* If the close operation can raise an exception, whoops! */
if (myClass.close() == false) {
break;
}
}
return false;
}
Copyright (c) 2001 DeLorme
24
finally Keyword, part 3
public void callMethodSafely() {
while (true) { /* How about this situation? */
try {
/* Call this method until it returns false. */
if (callThisOTherMethod() == false) {
return;
}
} finally {
continue;
}
} /* end of while */
}
Copyright (c) 2001 DeLorme
25
Steps of try…catch…finally
Every try block must have at least one catch or finally block
attached.
If an exception is raised during a try block:




The rest of the code in the try block is skipped over.
If there is a catch block of the correct, or derived, type in this stack
frame it is entered.
If there is a finally block, it is entered.
If there is no such block, the JVM moves up one stack frame.
If no exception is raised during a try block, and there is no
System.exit() statement:

If there is a matching finally block it is entered.
Copyright (c) 2001 DeLorme
26
Questions for Section Two
??
Copyright (c) 2001 DeLorme
27
Section Three
Designing an effective exception class hierarchy.
Java Exception Hierarchy
Throwable
The base class for all exceptions, it is required for a class to be
the rvalue to a throw statement.
Error
Any exception so severe it should be allowed to pass
uncaught to the Java runtime.
Exception
Anything which should be handled by the invoker is of this
type, and all but five exceptions are.
java.lang.Throwable
java.lang.Error
java.lang.ThreadDeath
java.lang.Exception
java.lang.RuntimeException
java.lang.NullPointerException
java.lang.IllegalArgumentException
Copyright (c) 2001 DeLorme
java.io.IOException
java.io.FileNotFoundException
29
Creating your own exception class
/* You should extend RuntimeException to create an unchecked exception,
* or Exception to create a checked exception. */
class MyException extends Exception {
/* This is the common constructor. It takes a text argument. */
public MyException(String p_strMessage) {
super(p_strMessage);
}
/* A default constructor is also a good idea! */
public MyException () {
super();
}
/* If you create a more complex constructor, then it is critical
* that you override toString(), since this is the call most often
* made to output the content of an exception. */
Copyright (c) 2001 DeLorme
30
Three Critical Decisions
How do you decide to raise an exception rather than return?
1.
2.
3.
Is the situation truly out of the ordinary?
Should it be impossible for the caller to ignore this problem?
Does this situation render the class unstable or inconsistent?
Should you reuse an existing exception or create a new type?
1.
2.
3.
Can you map this to an existing exception class?
Is the checked/unchecked status of mapped exception acceptable?
Are you masking many possible exceptions for a more general one?
How do you deal with subsumption in a rich exception hierarchy?
1.
2.
Avoid throwing a common base class (e.g. IOException).
Never throw an instance of the Exception or Throwable classes.
Copyright (c) 2001 DeLorme
31
An Example of Return v. Raise
try {
InputStream oStream = new URL("http://www.mainejug.org").openStream();
byte[] myBuffer = new byte[512];
StringBuffer sb = new StringBuffer();
int nCount = 0;
while ((nCount = oStream.read(myBuffer)) != -1) {
sb.append(new String(myBuffer));
}
oStream.close();
return sb.toString(); /* if sb.length() == 0 is NOT an exception. */
/* These, on the other hand, are certainly exceptional conditions. */
} catch (MalformedURLException mue) {
throw mue;
} catch (IOException ioe) {
throw ioe;
}
Copyright (c) 2001 DeLorme
32
Mapping to an Exception Class
When you attempt to map your situation onto an existing
Exception class consider these suggestions:




Avoid using an unchecked exception, if it is important enough to
explicitly throw, it is important enough to be caught.
Never throw a base exception class if you can avoid it:
RuntimeException, IOException, RemoteException, etc.
Be certain your semantics really match. For example,
javax.transaction.TransactionRolledBackException, should not be
raised by your JDBC code.
There is no situation which should cause you to throw the Exception
or Throwable base classes. Never.
Copyright (c) 2001 DeLorme
33
Using Unchecked Exceptions
Use unchecked exceptions to indicate a broken contract:
public void setName(String p_strName) {
/* This is a violated precondition. */
if (p_strName == null || p_strName.length() == 0) {
throw new InvalidArgumentException(“Name parameter invalid!”);
}
}
Be careful about creating a type derived from
RuntimeException.
A class derived from AccessControlException is implicitly unchecked
because its parent class derives from RuntimeException.
Copyright (c) 2001 DeLorme
34
Simple Type Subsumption
/* Since UnknownHostException extends IOException, the catch block
* associated with the former is subsumed. */
try {
Socket oConn = new Socket(“www.sun.com”, 80);
} catch (IOException ioe) {
} catch (UnknownHostException ohe) {
}
/* The correct structure is to arrange the catch blocks with the most
* derived class first, and base class at the bottom. */
try {
Socket oConn = new Socket(“www.sun.com”, 80);
} catch (UnknownHostException ohe) {
} catch (IOException ioe) {
}
Copyright (c) 2001 DeLorme
35
A Tricky Subsumption Problem
/* The catch block can perform any number of functions, a common pair is
* exception encapsulation and rethrow. */
try {
Connection oConnection = MagicPool.getInstance().getConnection();
Statement oStatement = oConnection.createStatement(“...”);
if (oStatement.executeUpdate() != 1) {
throw new CreateException(“Account could not be created.”);
}
/* Why is there a possible subsumption here? */
} catch (SQLException sqle) {
throw new CreateException(“Unable to create requested account, due to
internal error: “ + sqle.toString());
} catch (CreateException ce) {
throw ce;
} /* You know what we need here, eh? */
Copyright (c) 2001 DeLorme
36
Avoiding Type Subsumption
try {
Connection oConnection = MagicPool.getInstance().getConnection();
Statement oStatement = oConnection.createStatement(“...”);
if (oStatement.executeUpdate() != 1) {
throw new CreateException(“Account could not be created.”);
}
/* If this rethrow was missing, we would have a problem. */
} catch (CreateException ce) {
throw ce;
} catch (SQLException sqle) {
throw new CreateException(“SQL error in creating: “+sqle.toString());
}
/* This avoids a subsumption, if CreateException is derived from
* SQLException. Above is a good technique for handling this problem. */
Copyright (c) 2001 DeLorme
37
Subsumption Is Good Too!
public String getContent(String p_strURL)
throws MalformedURLException, IOException
{
URL myURL = null;
InputStream oStream = null;
/* Imagine more code here. */
}
If the code calling this is driven by a console application then subsuming
the MalformedURLException makes the code easier to write. The same
error text is output regardless of type.
If, on the other hand, the code is in use by a GUI, then catching the two
exceptions aids the development of features like URL repair. The
IOException is fatal, but the user can possibly resolve the URL problem!
Adrian says, “This example stinks.”
Copyright (c) 2001 DeLorme
38
Type Encapsulation
Because JDBC objects can raise lots of types of checked and
unchecked exceptions, and because they encapsulate resources
which must be released quickly, this pattern emerges:
public void load(PrimaryKey p_oKey) throws CreateException {
Connection oConnection = null;
Statement oStatement = null;
try {
/* Imagine code here! */
} catch (CreateException ce) {
throw ce;
} catch (ClassNotFoundException cnfe) {
throw new CreateException(“Caught Class!Found”+cnfe.toString());
} catch (SQLException sqle) {
throw new CreateException(“Caught SQLException”+sqle.toString());
} finally {
try { oStatement.close(); } catch (Exception e) { }
try {oConnection.close(); } catch (Exception e) { }
}
}
Copyright (c) 2001 DeLorme
39
Questions for Section Three
???
Copyright (c) 2001 DeLorme
40
Section Four
Advanced Exception Handling
The Utility of Backtracking
Backtracking is the process by which the stack frame is unwound
in the presence of an unhandled exception.
This process has some important properties:




Objects created on the stack are discarded to the GC.
Methods which cannot handle the exception are cleaned up implicitly.
Each stack frame has the ability to subsume the exception.
The end of the line is the JVM, which logs unhandled exceptions.
Under C++, each object discarded is immediately, and fully,
destroyed. This is a key problem for Java, and C#:
Copyright (c) 2001 DeLorme
42
finally and finalize(), siblings?
Java’s garbage collector (GC) offers each method a type of
destructor called ‘finalizer()’.
It is called with neither timing nor order guarantees, by the JVM.
This is called non-deterministic finalization and gives rise to serious
problems with Java objects which encapsulate OS resources:
network, graphics, and database objects.
Enter the finally block:
try {
/* Insert code here. */
} finally {
myResource.close();
}
Copyright (c) 2001 DeLorme
43
Bytecode Layout
Each method has a table of exception information at the start of it:




start_pc - where a try block begins
end_pc - where the try block ends, just before the first catch
catch_pc - the location of a catch block
catch_type - the class type caught by this catch block.
If a finally block is in use, then each statement which can exit the
try block has a special bytecode instruction attached to it (jsr).
This calls the special finally subroutine.
It is easy to see how a proliferation of try/catch blocks and many
finally blocks can quickly grow the code and the exception table on
the method.
Copyright (c) 2001 DeLorme
44
Bytecode Layout, part 2
public void foo() {
try { /* marks the start of a try-catch block: start_pc */
int a[] = new int[2];
a[4] = 1; /* causes a runtime exception due to the index */
/* end of the code in the try block: end_pc */
} catch (ArrayIndexOutOfBoundsException e) {/* catch_pc, catch_type */
System.out.println(“AIOOBE = " + e.getMessage());
} catch (NullPointerException npe) { /* catch_pc, catch_type */
System.out.println(“NPE = “ + npe.toString();
}
}
Copyright (c) 2001 DeLorme
45
Performance Issues
At a macro level you can make it easier on a JIT compiler by doing
the following:




Do not use exceptions to manage flow of control: exit a loop with a
status variable rather than raising an exception.
Place try blocks outside of a while loop, rather than inside it.
If you use a finally block, avoid having many exit paths in the content
of the block. Remember that each exit point has a JSR attached to it.
The single largest exception cost in a non-native runtime is the
creation of the exception, not the catching of it.
In general avoid exceptions in the tight, fast code of your
implementation. While the cost is minimal in JVM, the price rises
rapidly in the JIT…
Copyright (c) 2001 DeLorme
46
Exceptions and JIT Optimization
Optimizing a Java program at runtime, within the JIT, requires a
process called “path analysis”.
A path analysis graph describes the structure of the method in the
form of a graph. Each of the canonical control structures (e.g. if,
for, while, …) creates new nodes and edges on the graph.
In the presence of exceptions, new nodes and edges can be
created for each and every Potentially Excepting Instruction (PEI)
in the method encountered.
Considering the number of both checked an unchecked exceptions,
these secondary, exceptional, paths can proliferate quickly.
The larger the path analysis graph, the more difficult it is for the
JIT compiler to optimize the Java application.
Copyright (c) 2001 DeLorme
47
Bytecode to Machine Code
When the JIT compiler is generating machine code from the
bytecode it is optimized over and over again.
This optimization takes advantage of the path analysis graph, and
potentially reorders the work of a method.
Java’s clear and precise specifications for exception handling deter
reorder-based optimization. This is because program state must be
correct before each PEI is invoked. (Make your eyes big and say,
OOHH!)
To really understand what all this means I would advise reading
the presentation:

The Evolution of Optimization and Parallelization technologies for Java,
or why Java for High Performance Computing is not an oxymoron! by
IBM’s Vivek Sarkar.
Copyright (c) 2001 DeLorme
48
Why Runtime Exceptions are Not Checked
11.2.2
The runtime exception classes (RuntimeException and its subclasses) are
exempted from compile-time checking because, in the judgment of the
designers of Java, having to declare such exceptions would not aid
significantly in establishing the correctness of Java programs. Many of the
operations and constructs of the Java language can result in runtime
exceptions. The information available to a Java compiler, and the level of
analysis the compiler performs, are usually not sufficient to establish that
such runtime exceptions cannot occur, even though this may be obvious to
the Java programmer. Requiring such exception classes to be declared
would simply be an irritation to Java programmers.
For example, certain code might implement a circular data structure that, by
construction, can never involve null references; the programmer can then
be certain that a NullPointerException cannot occur, but it would be
difficult for a compiler to prove it. The theorem-proving technology that is
needed to establish such global properties of data structures is beyond the
scope of this Java Language Specification.
Copyright (c) 2001 DeLorme
49
Issues in Multithreaded Code
class MyThread implements Runnable {
public MyTask m_oTask = null;
public void run() {
if (m_oTask == null) {
throw new IllegalStateException(“No work to be performed!”);
} else {
/* Do the work of the thread. */
}
}
}
public void foo() {
MyThread oThread = new MyThread();
/* There is no way to get the exception from the run() method! */
new Thread(oThread).start(); /* Good reason for Runtime choice!! */
}
Copyright (c) 2001 DeLorme
50
Use a Callback Pattern
interface ThreadCallback {
public void threadException(Thread p_oThread, Exception p_oException);
public void threadSuccess(Thread p_oThread);
}
public MySubthread implements Runnable {
ThreadCallback m_oTarget = null; /* The target of our status info. */
public MySubthread(ThreadCallback p_oTarget) {
m_oTarget = p_oTarget;
}
public void run() {
try {
/* work is done here. */
} catch (SomeException se) {
m_oTarget.threadException(this, se); /* inform about problem. */
return;
}
m_oTarget.threadSuccess(this); /* indicate all went well! */
}
Copyright (c) 2001 DeLorme
51
Use the ThreadGroup class
Threads can be tied to an instance of the ThreadGroup class. This
instance is notified about any uncaught exceptions by one of its
member threads:
class java.lang.ThreadGroup {
/* lots of other methods deleted… */
public void uncaughtException(Thread t, Throwable e);
}
/* The thread startup will change to this: */
new Thread(oMyThreadGroup, oMyThread).start();
You can derive from ThreadGroup, and make your own class with its
own implementation of uncaughtException().
Then you can implement the listener pattern in your derived class and
broadcast exception events to interested parties.
Copyright (c) 2001 DeLorme
52
Exceptions and RMI
Owing to the presenters limited experience with RMI, David Ezzio will
speak for a moment on this interesting problem.
Copyright (c) 2001 DeLorme
53
Questions for Section Four
????
Copyright (c) 2001 DeLorme
54
Bibliography
Material for further reading
Links to this material is at:
http://www.backflip.com/members/cratliff
Section One
Goodenough, John B. Exception Handling: Issues and a Proposed
Notation. Communications of the ACM, 18(12), Dec 1975.
W. Kahan & J. Darcy. How Java’s Floating-Point Hurts Everyone
Everywhere. ACM 1998 Workshop on Java for High-Performance Network
Computing, March 1998.
Copyright (c) 2001 DeLorme
56
Section Two
R. Cartwright, E. Allen, and K. Charter. Intermediate Programming
(C212) Lecture Notes. Department of Computer Science, Rice
University, Spring 2001.
M. Robillard and G. Murphy. Analyzing Exception Flow in Java
Programs. Department of Computer Science, University of British
Columbia, 2 March 1999.
T. Suydam. Java Tip 91: Use nested exceptions in a multitiered
environment. JavaWorld, April 2001.
B. Venners. Under the Hood: Try-finally clauses defined and
demonstrated. JavaWorld, February 1997.
Copyright (c) 2001 DeLorme
57
Section Three
J. Gosling, B. Joy, G. Steele & G. Bracha. The Java Language
Specification, Second Edition. Sun Microsystems, 2000.
Copyright (c) 2001 DeLorme
58
Section Four
C. Austin & M. Pawlan. Advanced Programming for the Java2 Platform.
Addison Wesley, September 2000.
J-D. Choi, D. Grove, M. Hind, and V. Sarkar. Efficient and Precise Modeling of
Exceptions for the Analysis of Java Programs. IBM T.J. Watson Research Center.
M. Gupta, J-D. Choi, and M. Hind. Optimizing Java Programs in the
Presence of Exceptions. European Conference on Object-Oriented
Programming, Cannes France, June 14-16 2000.
P. Haggar. Multithreaded Exception Handling in Java. IBM Corporation.
V. Sarkar. Evolution of Optimization and Parallelization Technologies
for Java. IBM T.J. Watson Research Center, May 2000.
T. Suydam. Use nested exceptions in a multitiered environment.
JavaWorld.
Copyright (c) 2001 DeLorme
59