简体   繁体   中英

Catching explicit exceptions from a hierarchy

I have a set of exceptions under a base exception called ServiceException . These exception include explicit reasons for service failure - BadRequestException , ServiceUnreachableException to indicate behavior my classes can't fix themselves.

This hierarchy looks a little something like so:

public class ServiceException extends Exception {
    public ServiceException() { super(); }

    public ServiceException(String message) { super(message); }

    public ServiceException(String message, Throwable cause) { super(message, cause); }

    public ServiceException(Throwable cause) { super(cause); }
}

and an example of one of the sub-types:

import lombok.AllArgsConstructor;
import lombok.Getter;

@Getter
@AllArgsConstructor
public class ServiceUnreachableException extends ServiceException {
    private final String message;
    private final Throwable cause;
}

When I go to use this I would like to have the following structure:

public void doProcess() throws ServiceException {
   ...
}

public void processor() {

  try {
    doProcess()
  } catch (BadRequestException e) {
    // Handle specific exception
  } catch (ServiceUnreachableException e) {
    // etc
  } catch (InvalidApiKeyException e) {
    // ...
  }
}

this enables me to cleanly use the catch blocks to catch the various exceptions. It seems though that Java can't infer that the exceptions are thrown by the doProcess method explicitly via throws ServiceException .

This would lead me to believe I would need to do one of the following:

public void doProcess() throws BadRequestException, ServiceUnreachableException, InvalidApiKeyException {
   ...
}

public void processor() {

  try {
    doProcess();
  } catch (BadRequestException e) {
    // Handle specific exception
  } catch (ServiceUnreachableException e) {
    // etc
  } catch (InvalidApiKeyException e) {
    // ...
  }
}

or

public void doProcess() throws ServiceException {
   ...
}

public void processor() {

  try {
    doProcess();
  } catch (ServiceException e)  {
     if(e instanceof BadRequestException) {
       // cast and do stuff
     } else if(e instanceof ServiceUnreachableException) {
       // cast and do stuff
     } else if(e instanceof InvalidApiKeyException) {
        //cast and do stuff
     }
  }
}

Which seems more messy in exchange for the cleaner doProcess method definition.

Which is more correct here? They both work but I feel like the catch version is how you're supposed to use exceptions, and the other is a mess because doProcess decided to save a few lines by not explicitly enumerating all exceptions it throws.

Thank you!

It seems though that Java can't infer that the exceptions are thrown by the doProcess method explicitly via throws ServiceException .

No, it can't, because it has no way to be confident that it knows about all the subclasses of ServiceException that exist now or may exist in the future.

Which is more correct here?

It's not a question of correctness . Both approaches can get the job done. But I consider it poor style to catch a general exception and then use conditional expressions to select behavior for specific subtypes. You ought to use catch blocks to associate handlers with specific exceptions.

But I think you have asked the wrong question. Note well that there is a third alternative that is at least as good as the first:

public void doProcess() throws ServiceException {
   ...
}

public void processor() {
  try {
    doProcess();
  } catch (BadRequestException e) {
    // Handle specific exception
  } catch (ServiceUnreachableException e) {
    // etc
  } catch (InvalidApiKeyException e) {
    // ...
  } catch (ServiceException e) {
    // fallback for any other flavor of ServiceException
    // ...
  }
}

Of course, that supposes that you want to avoid processor() declaring any checked exceptions; else you could have it, too, throw ServiceException instead of providing a generic catch block for it.

Thus, the question you should be asking is not how to catch but what to throw. That's a design consideration that we haven't enough information to opine about.

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM