Java – Is returning an exception an anti-pattern

anti-patternserror handlingexceptionexception handlingjava

I have two simple methods:

public void proceedWhenError() {
   Throwable exception = serviceUp();

   if (exception == null) {
      // do stuff
   } else {
      logger.debug("Exception happened, but it's alright.", exception)
      // do stuff
   }
}

public void doNotProceedWhenError() {
   Throwable exception = serviceUp();

   if (exception == null) {
      // do stuff
   } else {
      // do stuff
      throw new IllegalStateException("Oh, we cannot proceed. The service is not up.", exception)
   }
}

The third method is a private helper method:

private Throwable serviceUp() {
    try {
        service.connect();
        return null;
    catch(Exception e) {
       return e;
    }
}

We had a small talk with a colleague of mine about the pattern used here:

returning an Exception (or Throwable) object from the serviceUp() method.

The first opinion:

It is an anti-pattern to use Exceptions to control the workflow and we should only return boolean from
serviceUp() and never the Exception object itself. The argument is
that using Exceptions to control the workflow is an anti-pattern.

The second opinion:

It is alright, as we need to deal with the object afterwards in the
two first methods differently and whether returning Exception object
or boolean does not change the workflow at all

Do you think 1) or 2) is correct and especially, why?
Note, that the question is ONLY about the method serviceUp() and its return type – boolean vs Exception object.

Note: I am not questioning whether to use Throwable or Exception objects.

Best Answer

It is an anti-pattern to use exceptions to direct the flow only when the exception is thrown in a non-exceptional situation*. For example, ending a loop by throwing an exception when you reach the end of a collection is an anti-pattern.

Controlling the flow with actual exceptions, on the other hand, is a good application of exceptions. If your method encounters an exceptional situation that it cannot handle, it should throw an exception, thus re-directing the flow in the caller to the exception handler block.

Returning a "naked" Exception object from a method, rather than throwing it, is certainly counter-intuitive. If you need to communicate the results of an operation to the caller, a better approach is to use a status object that wraps all the relevant information, including the exception:

public class CallStatus {
    private final Exception serviceException;
    private final boolean isSuccess;
    public static final CallStatus SUCCESS = new CallStatus(null, true);
    private CallStatus(Exception e, boolean s) {
        serviceException = e;
        isSuccess = s;
    }
    public boolean isSuccess() { return isSuccess; }
    public Exception getServiceException() { return serviceException; }
    public static CallStatus error(Exception e) {
        return new CallStatus(e, false);
    }
}

Now the caller would receive CallStatus from serviceUp:

CallStatus status = serviceUp();
if (status.isSuccess()) {
    ... // Do something
} else {
    ... // Do something else
    Exception ex = status.getException();
}

Note that the constructor is private, so serviceUp would either return CallStatus.SUCCESS or call CallStatus.error(myException).

* What is exceptional and what is not exceptional depends a great deal on the context. For example, non-numeric data causes an exception in Scanner's nextInt, because it considers such data invalid. However, the same exact data does not cause an exception in hasNextInt method, because it is perfectly valid.