Sie sind auf Seite 1von 52

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

slides overview
overview
designing exceptions using exceptions conclusion

slides overview
overview
designing exceptions using exceptions conclusion

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
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

Whether or not it leads to failure is a function of:


Adapted from: Mario Barbacci et. al, Quality Attributes, CMU/SEI-95-TR-021, Dec. 1995 ISBN 978-90-365-2788-0

terminology (contd)
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 doesnt 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

exception handling and error handling

Src: Hasan Szer, Architecting Fault-Tolerant Software Systems ISBN 978-90-365-2788-0

exception handling and dependability

Src: Hasan Szer, Architecting Fault-Tolerant Software Systems ISBN 978-90-365-2788-0

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 ,

what is an exception condition?


When an object cannot fulfill a responsibility for some reason
When some piece of code cant 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

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

error handling in older languages


Conventions were used for languages that do not support throwing and catching exceptions
Define a function that returns an unusual or illegal value when a run-time failure occurs
errorCodeType 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; }

Src: Allen B. Tucker , Programming Languages. Example by JavaPassion.org

exception handling in java


Helps you in
Separating error-Handling code from regular business logic code
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; } }

Propagating errors up the call stack


Grouping and differentiating error types Doesn't spare you the effort of doing the work of detecting, reporting, and handling errors,
But, they do help you in organizing the work more effectively

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

slides overview
overview
designing exceptions using exception conclusion

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

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

homogenize exceptions (contd)


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.

preserve encapsulation
Recast lower-level exceptions to higher-level ones whenever you raise an abstraction level
The exceptions abstraction level should be consistent with the interfaces abstraction

Adapted from: McConnell, Steve. Code Complete, 2nd Edition. Microsoft Press. 2004

preserve encapsulation (contd)


Why?
When low-level exceptions percolate up to a high-level handler, the handler has little context to make good exception handling decisions
To include the trace for the lower-level exception, you can use chain exceptions

Passing exceptions through different layers without abstraction will violate the principle of information hiding
It reduces reusability and clarity of the design

An exception thrown by an objects method is part of the interface

Therefore,
Throw UserPreferencesNotAvailableException from loadUserPreferences()
as opposed to an SQLException

Throw EmployeeDataNotAvailableException from Employee.getTaxId()


As opposed to an EOFException

Adapted from: McConnell, Steve. Code Complete, 2nd Edition. Microsoft Press. 2004

preserve encapsulation (contd)


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

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

precisely and completely specify exceptions at module/subsystem boundaries


Context - Modularized design: Compartmentalized programs with identifiable boundaries
Usually implemented at Java packages that have faade(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. 3.

make exceptions expressive and preserve encapsulation 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

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

know when to use checked and unchecked exceptions (contd)


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

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

strategies for handling abnormal situations (contd)


Recovery:
Perform an acceptable alternative Recovery could be as simple as using an alternate resource - a pen instead of a pencil Ask a human to apply judgment and steer the software to an acceptable resolution 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 Repeatedly attempt a failed action after recovering from failed attempts Makes sense only when there is a chance of success in the future

Appeal to a higher authority:

Rollback:

Retry:

Adapted from: Rebecca Wirfs-Brock, What It Really Takes to Handle Exceptional Conditions

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. Continue, but report condition to alternate log file and active console Report system unavailability to user and report backend request status when connection is reestablished

Failure to log transaction results to local database:


Failure to receive acknowledgment from backend system

Src: Rebecca Wirfs-Brock et. al, Object Design: Roles, Responsibilities, and Collaborations, Addison Wesley, ISBN: 0-20137943-0, Nov 2002

describe your exception handling design (contd)


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, dont go overboard.

Src: Rebecca Wirfs-Brock et. al, Object Design: Roles, Responsibilities, and Collaborations, Addison Wesley,

slides overview
overview
designing exceptions using exceptions conclusion

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.

Parameter public class BankAccount { value is illegal public void withdraw(double amount) { if (amount < 0) { throw new IllegalArgumentException("Amount is negative"); } balance = balance - amount; } ... }

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

do not try to handle coding errors (contd)


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 wont 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 wouldnt 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)?

do not catch or throw top-level exceptions


try { .. } catch (Exception e)) { .. } public void foo() throws Exception { ... }

In the above code, all exceptional situations in the same way


Including RuntimeException since RuntimeException is a subclass of Exception Hides bugs in your code

Sloppy code
Tells your callers something can go wrong in my method Defeats the purpose of using checked exceptions

If the code throws other checked exceptions later, you wouldnt be warned to handle them

do not catch or throw top-level exceptions (contd)


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, its 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

chain exceptions when translating an exception


Context
One good reason for recasting exceptions is to have the exception correspond to an objects/methods abstraction
private void init() throws InitializationException { ... } catch( FileNotFoundException cause) { throw new InitializationException(cause.getMessage()); } }

The call stack is lost, since the cause exception is not chained. Also, the original exception object (along with its state) is lost.

Chain exceptions to maintain call stack information


private void init() throws InitializationException { ... } catch( FileNotFoundException cause) { throw new InitializationException( Missing file, cause); }}

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

either log or throw but dont do both


catch (NoSuchMethodException e) { LOG.error("Blah", e); throw e; }
catch (NoSuchMethodException e) { LOG.error("Blah", 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

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

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 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 If a caller passes null in some parameter for which null values are prohibited, convention dictates that NullPointerException be thrown rather than IllegalArgumentException

IllegalStateException

NullPointerException

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-20137943-0, Nov 2002

provide context along with an exception (contd)


public class CustomerExistsException extends Exception{ property in the customer private String customerName; exception public CustomerExistsException(){} public CustomerExistsException(String message){super(message);} public CustomerExistsException(String message, String customer){ super(message); customerName = customer; } public String getCustomerName(){ return customerName; } }
Additional

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

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 cant 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

log exceptions effectively


Log exceptions only once
either log or throw but dont do both

Pay attention to log levels


... String productsRequest = prepareProductsRequest(productId); logger.debug (productsRequest); try { String response = retrieveProducts(productsRequest); logger.debug (response); } catch (NoSuchProductException e) { logger.error(e); ... // handle exception } catch (NoSuchProductException e) { } if (!logger.isDebugEnabled())

In production, if the log level is set as INFO or an upper level, request and response will not be available in the logs

Fix it as shown here

logger.error(request: + productsRequest); logger.error(e); // handle exception }

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. This gives you more confidence to assure correctness of the program.

A common use of assertions is to replace assumptions with assertions

Src: Programming With Assertions, Java 1.4 Documentation

use assertions to reaffirm assumptions


public BigInteger modInverse(BigInteger m) { if (m.signum <= 0) throw new ArithmeticException("Modulus not positive: " + m); ... // Do the computation assert this.multiply(result).mod(m).equals(ONE) : this; return result; }

Usage
Post-conditions

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

use assertions to reaffirm assumptions (contd)


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 methods contract
Throw exceptions such as IllegalArgumentException, NullPointerException, etc., here

The contract must always be obeyed whether assertions are enabled or disabled
Using assertions to check nonpublic methods precondition is ok.

private void setRefreshInterval(int interval) { // Confirm adherence to precondition in nonpublic method assert interval > 0 && interval <= 1000/MAX_REFRESH_RATE : interval; ... // Set the refresh interval }

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

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 dont do both handle exceptions as close to the problem as you can log exceptions effectively use assertions to reaffirm assumptions

in closing
Why dont we handle exceptions and errors well? Common excuses:
Its extra work, and I have a deadline looming
imagine watching a doctor performing an open heart surgery on you he has a deadline! unexpected things always happen, unlike the expected. And they mostly happen in production!

I know that this call will never return an error

I am just trying out something that works, and Ill 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
dont want to use my head figuring out points of potential failure

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 dont release their code until theyve 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

references
[Howell_Techni ques] [Renzel_Error_ Handling] [WirfsBrock_Excepti ons] [Wiki_Exceptio ns] [ObjectArchite cts_Error_Han dling] [McCune_Exc eption_Antipatt erns] Charles Howell and Gary Veccellio, Advances in Exception Handling Techniques (Alexander Romanovsky, ed., Springer 2001 Klaus Renzel, Error Handling for Business Information Systems A Pattern Language, 2011 Rebecca J. Wirfs-Brock, Toward Exception-Handling Best Practices and Patterns, Vol. 23, No. 5, September/October 2006, IEEE Computer Society http://c2.com/cgi/wiki?ExceptionPatterns http://www.objectarchitects.de/arcus/cookbook/exhandling/index.htm

Tim McCune, Exception-Handling Anti-Patterns, http://today.java.net/article/2006/04/04/exception-handling-antipatterns

[McConnell_C ode_Complete ]

McConnell, Steve. "Chapter 8 - Defensive Programming". Code Complete, Second Edition. Microsoft Press. 2004. Books24x7. http://common.books24x7.com/book/id_10482/book.asp

References (contd)
[Msdn_Excepti on_Guidelines] [Msdn_Excepti on_Block] [Szer_Fault_t olerant] [Cushing_Rule s_Exceptions] Design Guidelines for Exceptions, http://msdn.microsoft.com/enus/library/ms229014(VS.80).aspx Exception Handling Application Block, http://msdn.microsoft.com/enus/library/ff648029.aspx Hasan Szer, Architecting Fault-Tolerant Software Systems ISBN 978-90-365-2788-0 Jim Cushing, Three Rules for Effective Exception Handling, http://today.java.net/pub/a/today/2003/12/04/exceptions.html

Das könnte Ihnen auch gefallen