首页 > 解决方案 > 从层次结构中捕获显式异常

问题描述

我在一个名为ServiceException. 这些异常包括服务失败的明确原因 - BadRequestExceptionServiceUnreachableException以指示我的类无法自行修复的行为。

这个层次结构看起来有点像这样:

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); }
}

以及其中一种子类型的示例:

import lombok.AllArgsConstructor;
import lombok.Getter;

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

当我去使用它时,我希望有以下结构:

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

public void processor() {

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

这使我能够干净地使用 catch 块来捕获各种异常。尽管 Java 似乎无法推断出异常是由doProcess方法显式通过throws ServiceException.

这会让我相信我需要执行以下操作之一:

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) {
    // ...
  }
}

或者

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
     }
  }
}

为了换取更干净的doProcess方法定义,这似乎更混乱。

这里哪个更正确?它们都可以工作,但我觉得这个catch版本是你应该使用异常的方式,另一个是一团糟,因为doProcess决定通过不显式枚举它抛出的所有异常来节省几行。

谢谢!

标签: javaexceptionexception-handling

解决方案


尽管 Java 似乎无法推断出异常是由doProcess方法显式通过throws ServiceException.

不,它不能,因为它无法确信它知道ServiceException现在存在或将来可能存在的所有子类。

这里哪个更正确?

这不是正确性的问题。这两种方法都可以完成工作。但我认为捕获一般异常然后使用条件表达式为特定子类型选择行为的方式很糟糕。您应该使用catch块将处理程序与特定异常相关联。

但我认为你问错了问题。请注意,还有第三种选择至少与第一种一样好:

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
    // ...
  }
}

当然,这假设您要避免processor()声明任何已检查的异常;否则你也可以拥有它,ServiceException而不是为它提供一个通用的 catch 块。

因此,您应该问的问题不是如何捕捉而是扔什么。这是一个设计考虑,我们没有足够的信息来发表意见。


推荐阅读