That is an one catchy title. Okay okay, enough with puns.
One of the basic stuff for writing robust software is ability to handle errors when one occurs. This can be easily achieved with try-catch blocks. However, human-being tend to misuse solutions when the solution itself has a simple, straightforward set of instructions. Well, at least that is the case for me.
In todays writing, I will try to underline basic concept of try-catch shortly, after that I am going to give best practices for catching exceptions and handling them.
So, as always, lets get started!
Trying & Catching
It is a simple concept as I said before, when trying to execute a piece of code an error might be occur. That error could be a simply a null variable, missing file, a problem with arithmetic operations, missing method etc. After having these and such errors, in order to make software fault tolerant that errors should be caught and handled.
1try {2 // error prone code3} catch (Exception e) {4 // handling error5}
There are two more keywords in our tool-belt. Finally, which executed in any case, either error occurred or not; throw, which used when programmer want to throw exceptions manually.
Error vs Exception

When I was explaining try-catch I said “error”, but it was only to indicate unexpected situation. Technically unexpected errors have several types. Although, both Error and Exception is subclass of java.lang.Throwable, in realty Error and Exception is different things.
While Error is a serious problem for application, Exception is more reasonable problem that could and should be handled. When an Error occurs program has to terminate. An Error should never be caught.
Types of Exceptions
There are two types of exceptions: Checked and Unchecked. The difference between checked and unchecked exceptions whether checked at compile time or not. If method throws a checked exception it must either handle it or specify type of exception with throws
keyword. For unchecked exceptions it is not mandatory but programmers choice. In Java, all subclasses of RuntimeException
and Error
are unchecked exceptions, rest is checked exceptions. Also, by extending Exception
call, custom exceptions classes can be made to fulfill user requirements.
JVM Way of Handling Exceptions
When an Exception occurred, system looks for a handler that can appropriately process problem. The strategy that JVM follows is searching for an matching type of exception object and exception handler object in call stack. This searching operations is processed in call stack top to bottom, which means firstly it looks for the method that called last in timeline. If there is no match for exception objects than it looks for next method. Finally if there are no matching handler for thrown exception, JVM handles with default exception handler.
As can be seen in below, error propagated in call stack from top to bottom until exception type match. Since IOException
is checked exceptions in order to propagate throws
keyword should be used in method signatures. For unchecked exceptions throws keyword is not mandatory and not necessary. However in the case of checked exception without throws keyword and correct type of exception, program gives compile error.
1void makeHTTPCall() throws IOException {2 throw new IOException()3 // code here will not executed4}5void updateUserInfo() throws IOException {6 makeHTTPCall()7}8void getInfoFromUI() {9 try {10 updateUserInfo()11 } catch (IOException e){12 // handle exception13 }14}15void main() {16 getInfoFromUI()17}
1// call stack2makeHttpCall() // throws exception3updateUserInfo() // do not catches, propagete to further down in call stack4getInfoFromUI() // catches exceptions and handles5main()
Exception Features with Java 7
- try-with-resources
1try(BufferedReader br = new BufferedReader(new FileReader(path))) {2 return br.readLine();3}
It handles clean up operation made in finally
block
- Union catch block
1catch (FileNotFoundException | NullPointerException e) {2 // handle exception3}
Best Practices for Exception Handling
After throwing(pun intended) tedious part away, we can talk about best practices.
- Never swallow exception
1catch (Exception e) {2 return;3}4catch (Exception e) {5 // TODO: will be handled6}
- Always be specific about exception type
1void foo() throws Exception {2 // false3}4void foo throws FileNotFoundException {5 // true6}
- Handle most specific exception type first
1catch (NumberFormatException e) {2 log.error(e);3}4catch (IllegalArgumentException e) {5 log.error(e);6}
Beware that even if exception caught, lines after catch blocks will be executed.
- Only catch when it is possible to handle exception
- Do not only catch to re-throw exception
1catch (Exception e) {2 throw e; // not handled and re-throwed3}
- Correctly wrap exception with custom exceptions
1catch (Exception e) {2 throw new CustomException(e.getMessage()); // false3 throw new CustomException(e); // true4}
If it is not correctly wrapped, stack trace will be lost and it could be impossible to find where exception occurred. Although this practice seems to contradict with the previous one, wrapper exception class should have some logic in order to handle it or log the error.
- Either log or throw exception, not do both
1catch (Exception e) {2 log.error(e); // logged3 throw e; // logged again4}
Also, this one seems to contradict with the earlier ones, but re-throwing exception could be necessary in some specific scenarios.
Throw early catch late. In order to have all necessary information, catching should be made further down in call stack but throwing should be made as soon as possible.
Document exceptions with javadoc
As I said earlier, exceptions are very simple, but generally it is misused or forgetten. Covering simple set of instructions can be very useful in the long run, like solving a magical problem by simply catching and handling/logging. Also there is a more general way of handling exceptions with the aspect oriented programming but it is a different topic for another post.