首页 > 解决方案 > 是否可以将多个异常收集到一个自定义异常中?

问题描述

由于重构原因使用反射 API,我需要抛出重复出现的异常:

throws ApiException, ClassNotFoundException, NoSuchMethodException, IllegalAccessException, InvocationTargetException

这些异常总是出现在我使用重构方法的方法中,是否可以这样做:

throws CustomException

处理上面提到的所有异常?谢谢

标签: javaexception

解决方案


是的。有两种方法可以做到这一点:

类层次结构

这仅适用于是设计例外的人。如果这不能描述这种情况,请继续下一章。

例如,如果您有一个用户身份验证 API,您可能想要创建一整套异常,例如UserNotFoundExceptionIncorrectPasswordExceptionUserFrozenExceptionIpBlockedException等等。

如果您确保所有这些异常都扩展了一个异常类型 ( AuthenticationException),如下所示:

public class AuthenticationException extends Exception {
    public AuthenticationException(String msg, Throwable cause) {
        super(msg, cause);
    }

    public AuthenticationException(String msg) {
        super(msg);
    }
}

public class UserNotFoundException extends AuthenticationException {
    public UserNotFoundException(String username) {
        super(username);
    }
}

// and so on

然后调用者可以选择,这就是为什么这会产生如此出色的 API 设计。

如果调用者需要根据发生的身份验证问题的类型进行自定义反应,他们可以捕获,例如,UserNotFoundException. 但如果他们不是特别在意,他们可以抓住AuthenticationException

请注意,java 本身也这样做。GeneralSecurityException是常见的超类,但大多数与安全相关的方法都会抛出一个相当大的子类列表,这样调用者就可以准确地知道会发生什么样的错误,并且可以为特定的错误编写处理程序,而无需强迫他们编写大量的如果他们不想,就抓住块。

重新抛出

另一种解决方案是将异常捆绑到您自己的自定义类型中。

为此,首先编写一个异常(或使用现有的异常,但这在风格上很少是正确的举动)。然后,编写一个 catch 块并将所有那些奇怪的、不相关的异常包装到这个新创建的异常中,确保使用“原因”系统:

public class CustomException { // find a better name
    public CustomException(String msg, Throwable cause) {
        super(msg, cause);
    }

    public CustomException(String msg) {
        super(msg);
    }

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

public void myMethod() throws CustomException {
    try {
        // code here
    } catch (ApiException | ClassNotFoundException | NoSuchMethodException | IllegalAccessException e) {
        throw new CustomException(e);
    } catch (InvocationTargetException e) {
        throw new CustomException(e.getCause();
    }
}

但请注意,您只想一劳永逸的建议如何导致您的 API 设计出现问题。例如,像这样包装 InvocationTargetException 对您的 API 使用者来说是相当不利的;InvocationTargetException 本身就是一个包装器,所以现在你有了 wrappers-in-wrappers-in-wrappers ,这很丑陋,而且很难调用代码甚至试图以精确的方式处理问题。要阅读您使用的 API 并理解它为什么会抛出它抛出的各种异常,确实没有简单的方法。

注意:如果可以的话,类层次结构解决方案是一种更好的方法;但它确实要求您控制抛出它们的代码。


推荐阅读