Exception Handling Best Practices in Java

An exception is an event that occurs during the execution of a program that disrupts the normal flow of the program and the program terminates abnormally.

Types of Exception – the exception can be either a checked exception or an unchecked exception.

A method may not handle exception thrown within it and would instead throw it up the method call stack to let its caller know that an abnormal event occurred. It does so by declaring that exception in the throws clause of its declaration.
For example,

So in the above, in class A method doSomething() throws Exception so class A throws Exception. The method doSomething() does not do anything with the exception, so when method doSomething() in class B calls method doSomething() of class A it has to either handle that exception using try{}catch{} block or it has to declare throws in the class declaration to throw exception to its caller.

The caller itself may handle the exception thrown by its callee or in turn propagate that to its own caller.

In the above example, The method doSomething() does not do anything with the exception, so when method doSomething() in class B calls method doSomething() of class A, it handles the exception in the catch{} block.

Or if again method doSomething() in class B does not want to handle exception but wants to throw exception to its caller then it has to do the following

A method may translate an exception thrown by its callee into another exception and throw the new exception (to its own caller).

So if method doSomething() in class B wants to throw AppException() from its method then it has to wrap that exception to AppException() for throwing it by following way

Exception Handling Best Practices

1. Handle Exception close to its origin

It does not mean “catch and swallow i.e. suppress or ignore exception”

Non-compliant – only exception message is logged

Non-compliant – only exception object is logged

Non-compliant – only context message is logged

It means “log and throw an exception relevant to the source layer”

Compliant – context message and exception object are present

2. Throw DaoException from DAO layer and AppException from Business layer.

3. In applications using Web Services, the Web Service (a.k.a Resource) layer,
– should catch all exceptions and handle them by creating proper error response and send it back to client.
– should not allow any exception (checked or unchecked) to be “thrown” to client.
– should handle the Business layer exception and all other unchecked exceptions separately.


The catch handler for ‘Exception’ in the Web Service layer is expected to handle all unchecked exceptions thrown from within ‘try’ block

4. Log exception just once and log it close to its origin

Logging the same exception stack trace more than once can confuse the programmer examining the stack trace about the original source of exception.

5. When catching an exception and throwing it through an exception relevant to the source layer, make sure to use the construct that passes the original exception’s cause.

6. In case of existing code that may not have logged the exception details at its origin. In such cases, it would be required to log the exception details but do not overwrite the original exception’s message with some other message when logging.


DAO Layer:

Since logging was missed in the exception handler of the DAO layer, it is mandatory in the exception handler of the next enclosing layer – in this example it is the (Business/Processor) layer.

Business/Processor Layer:

7. Do not catch “Exception”

Accidentally swallowing RuntimeException

This code
– also captures any RuntimeException that might have been thrown by doSomething() method
– ignores unchecked exceptions and
– prevents them from being propagated

So, all checked exceptions should be caught and handled using appropriate catch handlers. And the exceptions should be logged and thrown to the outermost layer (i.e. the method at the top of the calling stack) using application specific custom exceptions relevant to the source layer.

8. Handle Exception before sending response to the Client

The layer of code component(i.e. the method at the top of the calling stack) that sends back response to the client, has to do the following:

– catch all checked exceptions and handle them by creating proper error response and send it back to client
– do not allow any checked exception to be thrown to the client
– handle the Business layer exception and all other checked exceptions raised from within the code in that layer separately
Examples of such components are:
– Service layer Classes in Web Service based applications
– Action Classes in Struts framework based applications


Exceptional case 1 for handling Exception

There would be rare situations where users would prefer an easy to understand message to be displayed to them, instead of the system defined messages thrown by unrecoverable exceptions. In such cases, the method at the top of the calling stack, which is part of the code that sends response to the client is expected to handle all unchecked exceptions thrown from within the try block. By doing this, technical exception messages can be replaced with generic messages that the user can understand. So, a catch handler for Exception can be placed in it. This is an exception to best practice 6 and is only for the outermost layer. In other layers downstream in the layered architecture, catching Exception is not recommended for reasons explained under best practice 6.


Exceptional case 2 for handling Exception

Certain other exceptional cases justify when it is handy and required to catch generic Exception. These cases are very specific but important to large, failure-tolerant systems.
Consider a request processing system that reads requests from a queue of requests and processes them in order.

With the above code, if any exception occurs while the request is being processed (either a BadRequestException or any subclass of RuntimeException including NullPointerException), then that exception will be caught outside the processing while loop.
So, any error causes the processing loop to stop and any remaining requests will not be processed. That represents a poor way of handling an error during request processing.
A better way to handle request processing is to make two significant changes to the logic.
1) Move the try/catch block inside the request-processing loop. That way, any errors are caught and handled inside the processing loop, and they do not cause the loop to break.     Thus, the loop continues to process requests, even when a single request fails.
2) Change the try/catch block to catch a generic Exception, so any exception is caught inside the loop and requests continue to process.

In situations where requests, transactions or events are being processed in a loop, that loop needs to continue to process even when exceptions are thrown during processing.

9. Handling common Runtime Exception


– It is the developer’s responsibility to ensure that no code can throw it
– Run null reference checks wherever it has been missed

NumberFormatException, ParseException

– Catch these and create new exceptions specific to the layer from which it is thrown (usually from business layer) using user-friendly and non technical messages
– To avoid ClassCastException, check the type of the class to be cast using the instanceof operator before casting.
– To avoid IndexOutOfBoundsException, check the length of the array before trying to work with an element of it.
– To avoid ArithmeticException, make sure that the divisor is not zero before computing the division.


All other unchecked exceptions i.e., RuntimeException, will be caught and handled by the Exception handler in the outermost or top layer.

Thanks for reading.


Software Professional, I am passionate to work on web/enterprise application. For more information please go to about me. You can follow on Twitter. You can be a friend on Facebook or Google Plus or Linkedin

Leave a Reply

Your email address will not be published. Required fields are marked *

Time limit is exhausted. Please reload CAPTCHA.