Exception Handling in Java: Asynchronous Exceptions and Important guidelines

Exception
Handling in Java: Asynchronous Exceptions and Important guidelines

Asynchronous
Exceptions

The
exceptions we have seen so far are synchronous in nature, in the sense that we
know the point in the program where they occur and when they happen, and we
process them immediately in the same thread. Contrary to this, an asynchronous exception
may occur at any point in the execution of a program.

For
example, an internal error generated by the JVM is a type of asynchronous exception—we don’t know when it will
occur. Similarly, when we execute a stop method of the Thread or ThreadGroup
class we cause an asynchronous exception in another thread. Handling such
exceptions is nontrivial and sometimes impossible to handle.

Guidelines
for Using Exceptions

We’ll
look at some guidelines on how to use exception handling efficiently in your
program code. Use exception handling judiciously. Wherever our program code can
perform a simple check to avoid errors, do it rather than waiting for the
exceptions to occur. In other words, do not use exception handling unless we
are required to do so.

Let’s
suppose we have written a stack class and have written a method, pop,
that pops an element from the stack. Before we perform a pop operation on the
stack, we must confirm that the stack is not empty. A simple check will reveal this
condition, and doing so will be more efficient than letting an exception occur
in the running code.

Another
example would be checking the number of command-line arguments passed to our
program. It would be more efficient to ensure that the user has indeed supplied
the required number of parameters rather than letting an exception occur in the
running code. In situations similar to our earlier example where an ArrayIndexOutOfBoundsException
occurred, the real fix for the array access exception is not to handle the exception,
but to fix the code.

Some
developers put the try/catch block on every possible statement in the program
code. This results in cluttering the code with several try/catch blocks and
obscures the program’s main logic. Organize all the suspected statements in a
single try block and provide multiple handlers to this try block. If
you prefer, you may throw the exceptions to the caller and centralize all the exception
processing, as discussed in previous posts.

Because
Java makes it mandatory to handle all the checked exceptions, oftentimes
programmers tend to provide an empty exception handler like the one shown here:

try {

// do something

} catch (Exception
e) {} // do not do this.

Never
do this, because if an exception occurs at any time, it will be silently
ignored. Ignoring an exception would result in an unpredictable program state,
which would be difficult to diagnose and fix.

Another
important question that comes to the programmer’s mind is, Should I handle the exception
or pass it on to somebody else? Whenever possible, handle the exception. It is
always better to handle the exceptions near the place where it occurs
initially. If we feel that centralizing the exception handling can improve the
code readability, feel free to pass the exception to the caller.

Also,
it is important that we make best use of the exception hierarchy. Wherever
possible, provide the handlers for the subclass exceptions rather than the most
generic exception. If the existing exception class does not adequately describe
the exception in your problem domain, create your own exception class.