There are always exceptions to the rule, right? In Java, those exceptions allow a clean break from normal program flow in the event of an exceptional situation. They're not used for program flow interruption, but for program flow branching, which can sometimes lead to difficult-to-maintain code. Marcus Zarra walks you through several best practices for using exceptions in Java.

Like this article? We recommend

The capability to throw exceptions in Java gives a much-needed flexibility to
the language. By being able to exit from the normal program flow, code can
remain clear and easy to maintain. As is usual, with this added flexibility
comes the temptation to abuse it. It is quite common to use exceptions as a way
to exit out of a method during normal program flow. Although this style of
programming is tempting, it is an abuse of exceptions that causes the code to be
difficult to maintain and debug.

Return Early, Return Often

One of the most common abuses of exceptions is an attempt to avoid returning
early. Edsger W. Dijkstra is often credited with claiming that methods should
always have a single exit point. Although I disagree that Dijkstra claimed this,
there has been a school of thought following the single exit point strategy.
Trying to force a single exit point in a Java method often leads to clunky and
unmaintainable code.

Programmers attempting to avoid layers and layers of nested code end up using
exceptions to exit early in an attempt to avoid multiple exit points. Following
this strategy, the programmer ends up with code that has to use a try/catch
block instead of a simple conditional. Imagine a method that throws an exception
instead of returning a false. The code that calls that method might look
something like this:

In this example, the catch block is used instead of a false result from the
chargeCustomerCard() method. Of course, this begs the question, what happens if
the chargeCustomerCard() throws a "real" exception? How is that
handled? That might lead to further confusion:

As you can see, this quickly gets out of hand. Normal program flow is getting
mixed up with exceptional situations. To avoid this, throw exceptions only for
exceptional situations and use return codes or boolean values to control program
flow:

This process not only produces code that is easier to read but it also allows
unexpected exceptions to bubble up through the code to be either dumped out by
the JVM or caught at a higher level.

Avoid putting yourself into this situation. If it makes sense to return from
a method early, do so. Don’t throw an exception just to avoid multiple
return points. In addition, check for known false results. If, in the above
example, variable1 must be of a certain length, check the length—if it is
wrong, return immediately. Returning early because of known bad situations will
make the code easier to read and keep the proper path on the left margin of the
method. This will be easier to maintain.