在 Java 中抛出多个检查异常有什么问题?

What's wrong with throwing multiple checked exceptions in Java?

考虑下面的 Java 代码片段:

public <T> T create(Class<T> clazz) throws InstantiationException, IllegalAccessException {
    return clazz.newInstance();
}

这是在 Eclipse(Neon.2,JDK8)中使用 SonarLint 执行静态代码分析。它提供了重构这个的建议:

Refactor this method to throw at most one checked exception instead of: java.lang.InstantiationException, java.lang.IllegalAccessException

此建议的基础是什么最佳做法?我知道一般来说有一些 controversy 关于检查的异常,但是为什么在这种情况下在这里捕获一个异常并将另一个传递到堆栈而不是将它们都传递到堆栈以供其他处理它们?

public class IllegalAccessException
extends ReflectiveOperationException

当应用程序试图以反射方式创建实例(数组除外)、设置或获取字段或调用方法时抛出 IllegalAccessException,但当前正在执行的方法无权访问指定class、字段、方法或构造函数的定义。

我同意@David 的观点,它是基于意见的,但在我看来,最好的做法是根据单一职责原则从方法中抛出一个异常。当抛出多个异常时,听起来该方法被实现为执行多个任务,这在理想情况下并不是一个好的做法,尽管我们每个人都经常这样做。当有这种需要时,最好通过使用适当的错误代码或错误消息提及问题来抛出自定义异常

What best practice is the basis for this recommendation?

"Best practice" 表示该问题只有一个客观正确的答案。一个都没有。

Why would it be better in this instance to catch one here and pass the other up the stack vs. passing them both up the stack for something else to handle them?

在这种情况下,您不会那样做。 IllegalAccessExceptionInstantiationException 都是 ReflectiveOperationException 的子类型。如果您想将签名减少为单个检查异常(如检查器所建议的),您将使用该异常。

一般来说,统一(通过选择现有的超类或通过重新设计异常层次结构)的论点是调用者需要处理更少的异常。

但与之相反的论点是,当您统一抛出列表时,您是在向程序员/编译器隐藏信息。例如,如果 API 更改为:

public <T> T create(Class<T> clazz) throws ReflectiveOperationException {
    ...
}

使用那个API的程序员不再知道可以抛出哪些反射操作异常。而当你 "unify" 通过捕获、包装和抛出一个新的异常时,情况更糟。

请注意,我并不是说这两种方法都是错误的。我的意思是上下文应该决定你采用哪种方法。换句话说,诉诸 "best practice" 是没有抓住要点的。