Managing exceptions correctly in Java is not as simple as it may sound, there are many wide extended bad practices and programmers who simply don’t care. But having good exception handling is essential to diagnose problems in production and to basically make the maintenance of the application easier. What follows are, in my opinion, the 4 main considerations to effectively handle exceptions in Java.
1.- An exception should only be handled once.
Handling an exception more than once is one of the most common mistakes when dealing with exceptions. There are two main anti patterns:
NEVER shallow an exception. This is, without a question, the most dangerous error when dealing with exceptions. Swallowing an exception = Making your application lie to you. Once that you shallow an exception there is no coming back. Any error caused as consequence of this first exception is going to be extremely hard to diagnose.
Exception handled more than once
Havin an exception handled more than once basically means that in its way out of the stack trace, more than one method catches the same exception. The two main scenarios when a exception is handled more that once are:
Log and throw exception.
Logging and throwing an exception, from a naive perspective, may seem like a valid approach, but is an approach that generates noise and lacks elegance. It lacks elegance because the exception is thrown again after being logged, causing further catch blocks in the stack trace to also deal with it and consequently force them to shallow the exception or to log duplicated information. To prove it let´s imagine that a method logs and throws again one exception, the following would be the main options for further catch blocks in the stack trace.
1) Log exception. This will cause a duplicate stack trace being printed in the logs.
2) Ignore exception, the exception will get to the top of the stack trace, and the JVM will handle it. This will also cause a duplicate stack trace in the logs.
3) Shallow exception. This is a common case of exception swallowing. It usually happens when we know the internals of the method we are calling and we know that the exception is already logged. As already mentioned, exception swallowing is very dangerous.
Don’t wrap runtime exceptions without adding more information.
This is another common scenario of handling an exception more than once that causes a lot of noise. It usually happens when inside a method we have to handle a checked exception, so the programmer decides to catch all the exceptions and wrap them in runtime exceptions. i.e.
catch (Exception e) throw new RuntimeException (e)
The issue with the code above, is that it will also catch all RuntimeExceptions, and it will wrap them in a new RuntimeException, which is useless, because it doesn´t add more information. A better approach would be:
catch (RuntimeException re) throw re catch (Exception e) throw new RuntimeException (e)
2.- Create your own type and tree of exceptions.
Having your own type of exceptions, and your own hierarchy of exceptions, have a lot of advantages.
– Code becomes more readable.
– Logs become more readable.
– Helps to standardize the output of the exceptions.
– Makes it easy to tell what is the source of the exception.
3.- Who should catch the exception?
Place catch blocks carefully, if you are not sure if you want to handle the exception, don’t handle it. In general, only use catch when:
a.- You need to provide graceful error recovery. For instance: every entry point of your code that faces the customer should have a try catch strategy. Remember always to handle the exception as late as possible, otherwise you will end up swallowing the exception or handling it more than once.
b.- You are forced. If you receive a checked exception and you don’t want to handle it just now, feel free to wrap it up in a RuntimeException, but NEVER, shallow the exception.
c.- In batch like process that loop through a series of elements. inside the loop, ALWAYS, catch all exceptions.
d.- You want to add more information to the exception. For instance: Wrap an exception in a more specific, more related to your domain exception.
4.- Understand the purpose and nature of the exceptions.
The root cause for most of the anti patterns when handling with exceptions is the fact that the developers don’t fully understand the nature and purpose of the exceptions. An exception represents unexpected exceptional behavior, which we can try to recover from or handle gracefully. Catching exceptions is the mechanism the application gives us to step in before the JVM deals itself with the exception, is the last frontier. Having this is mind
– Be careful with exceptions when creating new exceptions. When dealing with exceptions, don’t make much assumptions, if you try to do something smart and you cause a further exception, you will loose the first exception.
– Don’t use exceptions to handle standard business cases. They are better off handled by your standard Java code.