Introduction
Quotes: One of the unexpected benefits of exception handling is better performance because many errors can be processed centrally instead of after each function call. - by Bruce Eckel, the author of Thinking in Java.
-First, what is exception?
In JVM SPEC, an exception is defined to be an error that JVM would signal to a program if a program violates the semantic constrains of the Java programming language. But that’s not the complete fact, more generally, causing an exception is considered to be an exceptional condition or abnormal state that a program is in. So besides violating the semantic constrains of a programming language, which may be a critical and unrecoverable condition, breaking the assumption on the logic functionality of a program can also be considered to be exceptions. From a more formal perspective, every statement, method or generally, module are expected to fullfill some implicit or explicit contract, and an exception indicates the inability to fullfill the contract. Regardeless of the context of the specific programming languge (such as Java) exception handling mechanism, exception and error are interchangeablely used.
-Second, what is exception handling?
Informally speaking, exception handling is what you do about the exceptional condition. However, though an agreement on the defintion of exception are generally achieved, exception handling mechanisms are from time to time debated on. Generally, three techinques / mechanisms / notions are concerning with exception handling. First, exceptions can be identified by returning distinguished error values and handling exceptions is immediately done based on the error values. This is the most conventional way of identifying and handling exceptions. Many large system written in C or most conventional procedure languages utilize this way. Second, exceptions identifying and handling are distinguished from other features that a porgramming language provides. This can be found in many modern OO language such as C++ and Java. An Exception class (or method ?) is and can be designated for each kind of exceptional condition, and special satements with special keywords are introduced to notify ( or throw ) the condition and then handle the condition, usually at different places in your program. Third, exceptions are covered or at least not emphasized based on the assumption that a module and the client of a module take clearly divided responsiblities. This is mainly concerning an OO design principle called design by contract, DBC for short.
Old-fashioned style by returning distinguished error values
When encountering an error, return distinguished error values that are not considered normal return values. For example, a method that is to calculate the square root of a number doesn’t consider a negative number as a normal return value, so returning -1 / -2 / -3 indicates an error. The client code can distinguish a normal return value from error return values, so the client programmer can write code to cope with each exceptional condition according to returned error values, each of which indicate a kind of exceptional condition. E.g.,
int sqrt( int num )
{
if ( .. ) return -1;
else if ( … )
{
…
return -2;
}
…
}
-pros and cons
pros: Both notifying and handling exceptions are light weight. 1) No extra mechanisms are needed to notify and handle exceptional condition, which means codes notifying and handling exceptional conditions are executed in exactly the same way other codes that solving the core problems runs. 2) This will not introduce any extra runtime overhead for exception handling.
cons: 1) This idiom tend to cause spaghetti codes. It will complexicate your method codes by having to place many error checking codes. 2) Agreements on what each error value means must be established between the author and the user of the method. And if the same meaning of an error value must be used among more than one method, the global agreement is hard to be established. For instance:
return -1, if the passed in argument <>
3) For the client code, it is not enforced to handle any exceptional conditions. In other words, it’s completely up to the client programmer whether or not to handle any exceptional conditions. 4) In addition, even exceptional conditions are to be handled, duplicate codes must be written for each call of the mehod, that is, several calls to the same method requires several times of handling several same kind of exceptional conditions which means codes for handing exceptional conditions can’t be centralized and thus be reused. 5) More worse, handling exceptions must usually be followed immediately after recieving the error values, regardless of whether or not the then’s current context can provide enough information to handle the exceptions. That is, it is hard to propagate the exception to the right level of abstraction only on which such exceptions can be properly handled.
Exception handling style
Utilize dedicated constructs, such as Exception types, to represent the exceptions and collect information about the exceptional conditions, and handle exceptions based on information wrapped in such constructs.
-pros and cons
pros: 1) Exceptions and their handling are standardized as part of the features of a programming language that are distinguished from other features of that language. Handling some kinds of exceptions are enforced by the compiler, which means the learning curve are to some degree flattened. It less depends on the experiences, but are forced to be done. 2) Agreements on what exception means are easily established by the kind of dedicated constructs. And global reuse of these agreements needs no extra effort. 3) Though, it will stil cause spaghetti codes, it is alleviated by exception handling mechanism enabling that some exceptional conditions (such as access members on a null reference) are automatically notified in the standard way which means less error checking codes are needed. 4) Exceptions notifying and handling are loosely coupled, that is, identifying exceptions and handling them can be at two point far away from each othe in the control flow. This also means it is easy to propagate exceptions to the right level of abstraction on which such exceptions can be properly handled. 5) Due to easily propagating exceptions, handling the same kind of exceptions can be centralized, for which someone argues that unexpected performance benefits will be get as opposed to old-fashioned error values way.
cons: 1) Extra runtime overhead are needed to notify and handle exceptions for which at the implementation level, extra transfer of control is needed. 2) Client codes are complicated by exceptions handler codes which are more obvious if exceptions notifying are misued and/or overused.
Design by contract
A contract is established, explicitly or implicitly, between a module and the user (client code) of the module. Any side must comform to the contract at any time, under any circumstance. The contract consists of precondition, invariant and postcondition. Whenever wherever the module is called (used) the precondition must be met, and after executing the module, the postcondition must be met. In the whole process the invariant must always be met. Obligations and benefits for both parties are specified. It is the obligation of the client to ensure the precondition is met before calling the module, and that of the module to ensure the invariant and postcondition are met. So any party is committed to its obligation regardless of the other party’s obligation.
More specificly, the client will check and ensure the precondition is met before it calling the module, so on most occassions, no exception mechanism is needed. Because if the contract is always conformed to, no exceptions are foreseen. But, usually, extra mechanism, such as assertion, is needed to help tell and/or check whether or not the contract is conformed to. However, even no such extra mechanism is provided, the idea behind DBC can also be used to prevent from overusing exceptions which may be caused by defensive programming. In general, DBC is sometimes considered to be a formal method.
p.s., the DBC community considers returning error values and exception handling two rivals
Defensive programming
The philosophy of defensive programming can be summed up as: Better to check too much, or check redundantly, than to check little. This is in contrast to DBC which advocates guaranteeing more by checking less. It is conceivable that defensive programming is caused because the contract in DBC is not established at all. Actually, defensive programming goes to another extreme. It assumes that the other party never burden its obligation, such as ensuring the precondition, so the module will itself burden others’ obligations, such as checking for the precondition. This is mainly responsible for complexity and obscureness of codes. For instances, we have a module:
int sqrt( int num )
{
if precondition is met then
solve the problem; return …
else return …
}
and we have a snippet of client codes to call that module:
if preondition for sqrt( .. ) is met then
call sqrt( .. );
Pseudocodes in bold are caused by defensive programming. This way of programming are extensively common.
Exception handling in Java
When an exception is thrown, the JVM will transfer the control from the point where the exception occur to the point that can be specified by the programmer. During the process, the JVM abruptly completes, one by one, any expressions, statements, method and constructor invocations, static initializers, and field initialization expressions that have begun but not yet completed the execution in the current thread. The process continues until a handler for the thrown exception is found. If no such handler is found, then the method uncaughtException is invoked for the ThreadGroup that is the parent of the current thread.
If a finally clause is executed because of abrupt completion of a try block and the finally clause itself completes abruptly, then the reason for the abrupt completion of the try block is discarded and the new reason for abrupt completion is propagated from there.
If a method throws an exception, it must assume that exception is “caught” and dealt with. One of the advantages of Java exception handling is that it allows you to concentrate on the problem you’re trying to solve in one place, and then deal with errors from that code in another place.
Goal of exception handling
Make your program more reliable, robust and error-tolerant. Usually, it provides measures for you to be notified of the exceptional condition and recover from that condition.
Best practices in Exception handling
Below are some best practices in exception handling citing from the book “Effective Java”.
-Use exceptions only for exceptional condition
Prevent from overusing exception.
-Use checked exceptions for recoverable conditions and runtime exceptons for programming errors
Three kinds of exceptions: checked exception, unchecked exception and errors. By convention, errors must be used only by JVM. Programming errors may be considered to fail to fullfill the contract and are generally unrecoverable.
-Avoid unnecessary use of checked exceptions
Two reasons: first, exceptions handling needs extra runtime overhead; second, checked exceptions are forced to be caught which would complexicate your client code. This to some degree conforms to DBC by advocating the client code calls state-testing methods which actually is to ensure the precondition.
-Prefer standard exceptions over user-defined exceptions
For learning curve about your codes, understanability and portability of your codes.
-Throw exceptions appropriate to the abstraction
Exception translation, Exception chain.
-Document all exceptions thrown by each method
Javadoc style, or declaration using the keyword throws which is also called the exception specification.
Exceptions as a part of the specification of a method.
-Include failure-capture information in detail message
Refers to the goal of exception handling
-Strive for failure atomicity
Refers to the goal of exception handling
-Don’t ignore exceptions
No empty catch block.
Other guidelines
-User visible error message should not be the same as the failure message wrapped in the exception object (needs further investigation). The latter are only for programmer to debug the program.
-Don’t assume the way which the client codes burden their obligation and/or the degree to which they burden their obligations. However, unfortunately, defensive programming is often needed, though you should try your best to avoid.
Resources
- Chapter 8 Exceptions, Effective Java.
- 2.16 Exceptions, Java Virtual Machine Spec.
- Chapter 10 Error Handling with Exceptions, Thinking in Java 2nd version.
- Building bug-free O-O software: An introduction to Design by Contract(TM)
- Design By Contract
- Design By Contract (DBC)

No comments:
Post a Comment