1. WHAT EVERY PROGRAMMER MUST
KNOW ABOUT EXCEPTIONS
R AVI S HARDA
A PRIL -2011
“What we anticipate seldom occurs; what we least expected generally
happens.” – Benjamin Disraeli
4. terminology
• Failure
• A system fails when its behavior differs from that which was intended
• With respect to intent, and not with respect to the specification
• Error
• An error is a system state that is liable to lead to a failure if not
corrected
• A fault in a software system may or may not cause an error
• Whether or not it leads to failure is a function of:
• The redundancy in the system
• The system activity (the error may go away before it causes damage)
• what the user deems acceptable behavior. For instance, in data
transmission there is the notion of “acceptable error rate”
Adapted from: Mario Barbacci et. al, “Quality Attributes”, CMU/SEI-95-TR-021, Dec. 1995 ISBN 978-90-365-2788-0
5. terminology (cont…d)
• Fault
• A fault is the adjudged or hypothesized cause of an error
• May or may not cause an error
• For e.g., every exception thrown in your application doesn‟t lead
to an error
Adapted from: Mario Barbacci et. al, “Quality Attributes”, CMU/SEI-95-TR-021, Dec. 1995 ISBN 978-90-365-2788-0
6. exception handling and error handling
Src: Hasan Sözer, “Architecting Fault-Tolerant Software Systems” ISBN 978-90-365-2788-0
7. exception handling and dependability
Src: Hasan Sözer, “Architecting Fault-Tolerant Software Systems” ISBN 978-90-365-2788-0
8. what is an exception?
Tucker
• To throw an exception is to signal that the condition it represents
has occurred
• To catch an exception means to transfer control to an exception
handler, which defines the response that the program takes when
the exception occurs
Venners
• A structured way to perform a “go-to” from the place where an
error occurs to the code that knows how to handle the error
• Forces client programmers (those who use your code by calling
your methods) to deal with the possibility of an error condition
encountered by your code
Tucker - Allen B. Tucker , “Programming Languages” ,
9. what is an exception condition?
• When an object cannot fulfill a responsibility for some reason
• When some piece of code can‟t continue on its expected path
• Common causes:
• Users behaving incorrectly – entering wrong information or failing to respond
within a particular time
• Unavailable resources or requests to resources timing out
• Unauthorized requests
• Invalid requests such as malformed arguments
• Inconsistent state
• Dropped communications
• Bad data such as corrupt data, inconsistent data, missing files, etc.
• Coding or logic errors
• …
Src: Allen B. Tucker , “Programming Languages” & Rebecca J. Wirfs-Brock, “Toward Exception-Handling
Best Practices and Patterns” , Vol. 23, No. 5, September/October 2006, IEEE Computer Society
10. identifying points of failure
• Failure modes: “In what ways could this subsystem or
component fail?”
• Effects of failure: “What effects would the failure have, as
perceived by the customer?”
• Wirfs-Brock: Focus on collaborations among
• objects that interface to the user and the rest of the system
• objects within the system and objects that interface with external
systems
• objects outside a neighborhood and objects inside a neighborhood
• objects in different layers
• objects at different abstraction levels
• objects of your design and objects designed by someone else
• your objects and objects that come from a vendor-provided library
Rebecca Wirfs-Brock, “What It Really Takes to Handle Exceptional Conditions”
11. error handling in older languages
errorCodeType readFile {
initialize errorCode = 0;
open the file;
• Conventions were used for if (theFileIsOpen) {
determine the length of the file;
languages that do not support
if (gotTheFileLength) {
throwing and catching allocate that much memory;
exceptions if (gotEnoughMemory) {
read the file into memory;
• Define a function that returns an
if (readFailed) {
unusual or illegal value when a
errorCode = -1;
run-time failure occurs }
} else {
errorCode = -2;
}
} else {
errorCode = -3;
}
…
Src: Allen B. Tucker , “Programming Languages”. Example by JavaPassion.org
12. exception handling in java
readFile {
Helps you in try {
open the file;
Separating error-Handling
determine its size;
code from “regular” business
logic code allocate that much memory;
read the file into memory;
Propagating errors up the call close the file;
stack } catch (fileOpenFailed) {
Grouping and differentiating doSomething;
error types } catch (sizeDeterminationFailed) {
doSomething;
} catch (memoryAllocationFailed) {
• Doesn't spare you the effort of doSomething;
doing the work of detecting, } catch (readFailed) {
reporting, and handling errors,
doSomething;
• But, they do help you in } catch (fileCloseFailed) {
organizing the work more doSomething;
effectively
}
}
13. dealing with abnormal situations
• Does your software really need to break easily in reaction to
such failures?
• Trip up immediately
• Worse yet, fail in unpredictable ways
• Exception handling == Dealing with abnormal situations
Allows you to make your software robust and reliable
• Robustness: A robust program always terminates in a defined way, so
that behavior is predictable for all possible inputs.
• These include protection against incorrect usage, degenerate inputs and all
kinds of errors.
• Reliability: The ability of a system to deliver its normal service in
presence of errors and unexpected or incorrect usage (user errors).
• Two aspects of reliability can be distinguished: Fault Tolerance and
Robustness
15. make exceptions expressive
• Name an exception after what went wrong, not who raised it
• Why?
Makes it easy to associate the situation with the appropriate action to
take
If you name an exception after who threw it, it becomes less clear why
the handler is performing the specific action
try {
authenticator.authenticate(userName, password);
} catch (TooManyLoginAttemptsException(e)) {
// handle too many login attempts
}
Examples from Java API:
FileNotFoundException, EOFException, MalformedURLException,
SQLIntegrityConstraintViolationException, SQLSyntaxErrorException
Src: Rebecca Wirfs-Brock, “What It Really Takes to Handle Exceptional Conditions”
16. homogenize exceptions
• Convert/homogenize exceptions - at package/subsystem
boundaries, or, for a related sets of exceptions
• Why?
• If you let checked exceptions propagate without much thinking,
• you must have then all defined in your throws clause.
• Callers have to handle and potentially throw them in turn to their callers
• Anytime you change your method, the calling method and its callers in turn
may need to change their throws clause
• How?
• Declare one exception class per logical subsystem, or for a related sets of
exceptions
• Applies to subsystem only, therefore, not in conflict with “make expressions
expressive”
• Have other exceptions derive from the subsystem base exception
• Callers can then name a single superclass in a catch block instead of all the
individual exception classes for which a corrective action is appropriate
Src: http://c2.com/cgi/wiki?ExceptionPatterns
17. homogenize exceptions (cont…d)
Examples from Java API:
• IOException
• Subclasses: CharacterCodingException, ClosedChannelException,
EOFException, FileNotFoundException,
HttpRetryException,MalformedURLException,
UnsupportedEncodingException, UTFDataFormatException, etc.
• Example from Hibernate
• HibernateException
• Subclasses: IdentifierGenerationException, LazyInitializationException,
NonUniqueObjectException, TooManyRowsAffectedException, etc.
• QueryException
• QuerySyntaxException, QueryParameterException, etc.
20. preserve encapsulation (cont…d)
• Motivating example
• Exceptions can occur at many levels of abstraction in a platform
• At the hardware level, exceptions include illegal operations such
as division by 0, illegal memory references such as segmentation
faults and bus errors.
• At the programming languages level, exceptions include those
caused by events such as out-of-bounds array index, an attempt
to read to value to the wrong type, or an attempt to access an
object in the heap by using a null pointer.
• The hardware and the programming language preserve
encapsulation when they handle and propagate faults, leading to
a clean separation of concerns during abnormal situations
21. mapping error codes to exception
Context
• “Error codes” give a classification of different error situations
• An encoding for the type of a fault
• They are primarily an idiom for 3GL languages
• Because no exception mechanism is available in 3GLs, error propagation must be
done by normal control and data flow.
• However, in some situations they may be of use in languages such as Java
• Different parts of a system are implemented in different programming languages
• Internationalization of error messages
• When you provide libraries to others and want to hide exception traces from customers,
but need enough information to debug when customers report problems
• For e.g., Oracle Weblogic error codes
• Sometimes it may be simply impractical to map every error type to an exception class
type. Define a general error type with an error code property.
• For e.g., NoResponseFrom<ExternalSystemName>Exception mapping to time outs, b)
unavailable, hung state, etc.
Adapted from: Klaus Renzel, “Error Handling for Business Information Systems – A Pattern Language”, 2011
22. precisely and completely specify exceptions at
module/subsystem boundaries
• Context - Modularized design: Compartmentalized programs
with identifiable boundaries
• Usually implemented at Java packages that have façade(s) with
public methods. Access to sub-packages, internal classes/methods is
prevented through careful design
• Design of exceptions at module boundaries
1. Description of exceptions should be complete and precise
• Complete: every possible exception – checked or unchecked must be
specified
• Precise: If the exceptions that can be propagated are organized in an
inheritance hierarchy, all exceptions should be specified, not only the
super type
2. “make exceptions expressive” and “preserve encapsulation”
3. Use checked exceptions (often abstract exceptions)
• Even if you omit checked exceptions for module-internal functions
Adapted from: Martin P. Robillard and Gail C. Murphy, “Designing Robust Java Programs with Exceptions” & Mayaleri ,et. Al
23. Know when to use checked and
unchecked exceptions
Context
• Checked exceptions
• Java compiler checks if the program either catches or lists the
occurring checked exception
• If not, compiler error will occur
Forces the programmer to deal with the exceptional condition
• Unchecked exceptions
• Not subject to compile-time checking for exception handling
• Built-in unchecked exception classes: Error, RuntimeException,
and their subclasses
• Handling all these exceptions may make the program cluttered
and may become a nuisance
24. know when to use checked and
unchecked exceptions (cont…d)
• Use checked exceptions when the situation is treatable
• Recoverable conditions
• When a method is unable to fulfill its contract. The contract
includes preconditions that the client must fulfill and post
conditions that the method itself must fulfill.
withdrawMoney() throws NotEnoughMoneyException
• Use unchecked exceptions to signal an untreatable
situation
• Programming/coding errors
• If the contract assumptions are broken
• For e.g., IllegalArgumentException if inputs are invalid
25. strategies for handling abnormal
situations
• Inaction:
• Ignore the request after determining it cannot be correctly performed
Simple but leaves the client uninformed
• Balk (or organized panic):
• Admit failure, clean up the environment and return an indication to the
requestor (by either raising an exception or reporting an error condition
At least the requestor knows about the failure and could try an alternative
strategy
• Guarded suspension:
• Suspend execution until conditions for correct execution are established,
then try to perform the request
• Provisional action:
• Pretend to perform the request, but do not commit to it until success is
guaranteed
Makes sense when a request takes time and can be partially fulfilled in
anticipation of it later completing it
Adapted from: Rebecca Wirfs-Brock, “What It Really Takes to Handle Exceptional Conditions”
26. strategies for handling abnormal
situations (cont…d)
• Recovery:
• Perform an acceptable alternative
• Recovery could be as simple as using an alternate resource - a pen
instead of a pencil
• Appeal to a higher authority:
• Ask a human to apply judgment and steer the software to an
acceptable resolution
• Rollback:
• Try to proceed, but on failure, undo the effects of a failed action
• Common strategy where either all or nothing is desired and partial
results are unacceptable
• Retry:
• Repeatedly attempt a failed action after recovering from failed
attempts
• Makes sense only when there is a chance of success in the future
Adapted from: Rebecca Wirfs-Brock, “What It Really Takes to Handle Exceptional Conditions”
27. describe your exception handling design
• Document these exception handling with existing
collaborations
• Accompany a happy path collaboration diagram with commentary
that describes exceptions that you considered at each step.
Examples:
• Network fails during attempt to send request to backend:
• Detect that response times out. Retry request after communications
are restored. If too much time elapses, inform user of system
unavailability and fail the transaction.
• Failure to log transaction results to local database:
• Continue, but report condition to alternate log file and active console
• Failure to receive acknowledgment from backend system
• Report system unavailability to user and report backend request
status when connection is reestablished
Src: Rebecca Wirfs-Brock et. al, “Object Design: Roles, Responsibilities, and Collaborations”, Addison Wesley, ISBN: 0-201-
37943-0, Nov 2002
28. describe your exception handling design
(cont…d)
• Describing exceptions in a UML diagram
• In UML, an exception is modeled as a signal
• To show that an object raises an exception, draw an
asynchronous message between it and the client whose request
caused the exception
However, don‟t go overboard.
Src: Rebecca Wirfs-Brock et. al, “Object Design: Roles, Responsibilities, and Collaborations”, Addison Wesley,
30. validate inputs to your public interface
• Every method that is a part of the public interface must
validate its input parameters
• Usually a unchecked exception needs to be thrown as the contract is
violated
• The message associated with each exception must specify
(for a developer) in what way the parameter was invalid.
public class BankAccount { Parameter
value is illegal
public void withdraw(double amount) {
if (amount < 0) {
throw new IllegalArgumentException("Amount is negative");
}
balance = balance - amount;
}
...
}
31. do not try to handle coding errors
• For coding errors, the best strategy is to fail fast
• Do not catch unchecked exceptions
• Do not try to handle every null pointer exception, out-of-bounds
array index, divide-by-zero error, etc.
• Leave an audit trail of the problem that can be used to
troubleshoot it
• “Log exceptions effectively”
• A variant is a “library situation”
• Caller has broken the contract of your method – say by passing a
bizarre argument
• Fail-fast by throwing an unchecked exception
32. do not try to handle coding errors
(cont…d)
• Example: Say your code has a auto-save feature that works
every 10 minutes.
• What should you do if your auto save method threw an unchecked
exception?
• Should you crash out (by not handling it)?
• Yes!
• A bug is a bug is a bug: “You want to discover if your parachute won’t
work, sooner rather than later”
• Fix the logic that led to the unchecked exception, rather than work around
it
• Bottomline: prevent rather than catch coding errors
• Another example:
• You wouldn‟t want Excel to crash
• but it would be much worse if it ever produced an incorrect value in a
spreadsheet that I use to manage my personal finances.
Adapted from: Nick Guerrera, “FAQ: Why does FxCop warn against catch(Exception)?”
33. do not catch or throw top-level exceptions
try {
.. public void foo() throws Exception {
} catch (Exception e)) { ...
.. }
}
• In the above code, all • Sloppy code
exceptional situations in
the same way • Tells your callers
“something can go
• Including RuntimeException
since RuntimeException is a wrong in my method”
subclass of Exception • Defeats the purpose of
• Hides bugs in your code using checked
• If the code throws other exceptions
checked exceptions later,
you wouldn’t be warned to
handle them
34. do not catch or throw top-level exceptions
(cont…d)
• A variation
public void method1 throws OurAppBaseException {...}
public String method2 throws OurAppBaseException {
...
} catch( FileNotFoundException e ) {
throw new OurAppBaseException(e.getMessage( ), e);
}
}
• Having base exceptions serves some purposes (mostly for
management of exceptions)
• Common behavior such as serialization, etc.
• However, it‟s a design bug to have methods throw them as blanket
declarations
• The purpose of checked exceptions to provide specific information to
the caller about exceptions that might be thrown in a method
• The above practice undermines that purpose
35. chain exceptions when translating an
exception The call stack is lost, since the cause
exception is not chained.
Also, the original exception object
• Context (along with its state) is lost.
• One good reason for recasting exceptions is to have the
exception correspond to an object‟s/method‟s abstraction
private void init() throws InitializationException {
...
} catch( FileNotFoundException cause) {
throw new InitializationException(cause.getMessage());
}
}
• Chain exceptions to maintain call stack information
private void init() throws InitializationException {
...
} catch( FileNotFoundException cause) {
throw new InitializationException(
“Missing file”, cause);
}}
36. chain exceptions when translating an
exception
• How?
• Constructor of an exception object takes a „nested‟ or „cause‟ exception
as an argument
RemoteException(String s, Throwable ex)
ServletException(String message, Throwable rootCause)
• The newly created higher level exception object will then maintain a
reference to the underlying root cause exception
• If the higher level exception is called to print its stack trace, it will
include the stack trace of the root exception as part of its own output
37. either log or throw but don‟t do both
catch (NoSuchMethodException e) { catch (NoSuchMethodException e) {
LOG.error("Blah", e); LOG.error("Blah", e);
throw e; throw new MyServiceException("Blah",e);
} }
• Both of the above examples are equally wrong
• Among the most annoying antipattern
• Either log the exception, or throw it, but never do both
• Why?
• Logging and throwing results in multiple log messages for a
single problem in the code, and makes life hell for the support
engineer who is trying to dig through the logs
Src: Tim McCune, “Exception-Handling Antipatterns”
38. do not throw exceptions from within
finally
try {
blah();
} finally {
cleanUp();
}
• The code is fine as long as cleanUp() can never throw
an exception
• If blah() throws an exception, and then cleanUp() throws an
exception, the second exception is thrown and the first one
is lost!
• If the code you call in finally block can possibly throw an
exception, handle it, or log it
• Never let it bubble out of the finally block
39. favor the use of standard exceptions
Reuse standard exceptions in Java API
• IllegalArgumentException:
• thrown when the caller passes in an argument whose value is
inappropriate
• IllegalStateException
• thrown if the invocation is illegal, given the state of the receiving
object
• For e.g., if the caller attempted to use some object before it had been
properly initialized
• NullPointerException
• If a caller passes null in some parameter for which null values are
prohibited, convention dictates that NullPointerException be thrown
rather than IllegalArgumentException
• …
40. provide context along with an exception
• Exceptions in Java are objects and can be rich information
holders
• Values of parameters that caused the exception to be raised
• detailed descriptions
• error text
• information that can be used to take corrective action (for e.g.,
current no. of retries)
• Why?
• What's most important to the exception handler is to identify the
exception and to gain information that will aid it in making a more
informed response
Src: Rebecca Wirfs-Brock et. al, “Object Design: Roles, Responsibilities, and Collaborations”, Addison Wesley, ISBN: 0-201-
37943-0, Nov 2002
41. provide context along with an exception
(cont…d)
Additional
public class CustomerExistsException extends Exception{ property in the
private String customerName; customer
exception
public CustomerExistsException(){}
public CustomerExistsException(String message){super(message);}
public CustomerExistsException(String message, String customer){
super(message);
customerName = customer;
}
public String getCustomerName(){ return customerName; }
}
“With exceptions as objects, you have the power to encapsulate an unlimited
variety of functionality specific to the problem.”
- http://www.churchillobjects.com/c/11012k.html
42. handle exceptions as close to the
problem as you can
• Often, the object best equipped to make a decision is the
immediate caller
• If the caller knows enough to perform a corrective action, you can
rectify the condition on the spot
• Why?
• If you propagate an exception far away from the source, it can be
difficult to trace the source
• Often objects further away from the problem can‟t make meaningful
decisions.
• Note: sometimes the most able object is one that has been
explicitly designed to make decisions and control the action
• Controllers are naturals for handling exceptions as well as directing
the normal flow of events
Src: Rebecca Wirfs-Brock, “What It Really Takes to Handle Exceptional Conditions”
43. log exceptions effectively
In production, if
the log level is
• Log exceptions only once set as “INFO” or
an upper level,
• “either log or throw but don’t do both” request and
response will
• Pay attention to log levels not be available
in the logs
...
String productsRequest =
prepareProductsRequest(productId);
logger.debug (productsRequest);
try {
String response = retrieveProducts(productsRequest);
Fix it as
logger.debug (response);
shown here
} catch (NoSuchProductException e) {
logger.error(e); ...
// handle exception } catch (NoSuchProductException e) {
} if (!logger.isDebugEnabled())
logger.error(“request: ” + productsRequest);
logger.error(e);
// handle exception
}
44. use assertions to reaffirm assumptions
• Context
• Exception handling deals with unusual circumstances during program
execution (robustness)
• Assertions Overview
• Introduced in Java 1.4
• Are checked at run time and can be turned on and off
• Are by default disabled. Use the switch –enableassertions, or –ea to enable
them
• Failed assertions generate exceptions
• Usage
• Assertions are to assure the correctness of the program (Internal consistency
and validity checks)
• For example, if you write a method that calculates the speed of a particle,
you might assert that the calculated speed is less than the speed of light.
• A common use of assertions is to replace assumptions with assertions
• This gives you more confidence to assure correctness of the program.
Src: “Programming With Assertions”, Java 1.4 Documentation
45. use assertions to reaffirm assumptions
public BigInteger modInverse(BigInteger m) {
if (m.signum <= 0)
throw new ArithmeticException("Modulus not
positive: " + m);
... // Do the computation
• Usage assert this.multiply(result).mod(m).equals(ONE) :
this;
• Post-conditions return result;
}
• Pre-conditions (only on non-public methods) – See next slide
• Class invariants
• A type of internal invariant that applies to every instance of a class
at all times, except when an instance is in transition from one
consistent state to another
• For example, suppose you implement a balanced tree data
structure of some sort. A class invariant might be that the tree is
balanced and properly ordered. // Returns true if this
// tree is properly balanced
private boolean balanced() {
...
}
…// assert balanced();
Src: “Programming With Assertions”, Java 1.4 Documentation
46. use assertions to reaffirm assumptions
(cont…d)
• Do not use assertions for argument checking in public
methods
• Valid arguments that may be passed to a public method are
considered to be part of the method‟s contract
• Throw exceptions such as IllegalArgumentException,
NullPointerException, etc., here
• The contract must always be obeyed whether assertions are
enabled or disabled
private void setRefreshInterval(int interval) { Using assertions
// Confirm adherence to precondition in nonpublic method to check
nonpublic
assert interval > 0 && interval <= 1000/MAX_REFRESH_RATE : method’s
interval; precondition is
ok.
... // Set the refresh interval
}
47. summary
• Exceptions design practices
• make exceptions expressive
• homogenize exceptions
• preserve encapsulation
• mapping error codes to exception
• precisely and completely specify exceptions at
module/subsystem boundaries
• Know when to use checked and unchecked exceptions
• strategies for handling abnormal situations
• describe your exception handling design
48. summary
• Exceptions usage practices
• validate inputs to your public interface
• do not try to handle coding errors
• do not catch or throw top-level exceptions
• do not throw exceptions from within finally
• favor the use of standard exceptions
• provide context along with an exception
• chain exceptions when translating an exception
• either log or throw but don‟t do both
• handle exceptions as close to the problem as you can
• log exceptions effectively
• use assertions to reaffirm assumptions
49. in closing
• Why don’t we handle exceptions and errors well? Common
excuses:
• It‟s extra work, and I have a deadline looming
• imagine watching a doctor performing an open heart surgery on you – he
has a deadline!
• I know that this call will never return an error
• unexpected things always happen, unlike the expected. And they mostly
happen in production!
• I am just trying out something that works, and I‟ll take care of
“exceptional” scenarios later !
• “later” never comes
• Error handling clutters up the flow of the code, making it harder to read,
and harder to spot the “normal” flow of execution
• “don’t want to use my head figuring out points of potential failure”
50. in closing
• Robert C. Martin (Uncle Bob): 97 Things Every
Programmer Should Know
• Professionals take responsibility for the code they write
• They do not release code unless they know it works.
• They expect QA to find nothing because they don‟t release their
code until they‟ve thoroughly tested it.
• Of course, QA will find some problems, because no one is perfect.
• Professionals do not tolerate big bug lists (tragedies of
carelessness)
• Professionals do not make a mess
• They take pride in their workmanship