我应该声明从方法签名中的方法抛出的所有exception还是仅仅exception的超类?

当我从方法中抛出已检查的exception时,我应该在方法签名中声明exception的超类还是所有不同的类型? 如果我有以下例外:

private class SuperException extends Exception { } private class SubExceptionOne extends SuperException { } private class SubExceptionTwo extends SuperException { } 

方法签名应该是:

  void confirmAccount() throws SubExceptionOne, SubExceptionTwo; 

要么

  void confirmAccount() throws SuperException; 

在最后一个方法签名中,如何告诉其他开发人员可以从该方法抛出哪些exception? 如果不同的子类型需要不同的处理?

界面应尽可能稳定。 所以可能超级。 许多图书馆使用“超级”策略,因为exception规范导致可维护性比他们添加的可读性或安全性更令人烦恼。 甚至IOException都是Super,几乎所有Java库代码都使用它,而不是声明更具体的exception。 (但是当它们确实声明了更具体的exception时,这是因为合同是不会抛出更普遍的IOExceptions。请继续阅读。)

你可以列出Sub1和Sub2,如果你真的想说可以抛出每个exception,但不想说可以抛出Super的任何衍生物。 也许Sub1是NumberCrunchException,你的方法调用crunchNumbers(),你的方法的用户可以放心,这是你的方法唯一的例外。 在这种情况下,具体策略更好。

throws子句用于向调用方法传递有用信息,以了解在调用此方法时可能出现的问题。 这意味着你的具体程度取决于你想传达多少信息; 这将取决于应用程序。

例如,声明throws Exception几乎总是一个坏主意:这传达的信息只是“可能出错的东西”,这太模糊而无用。 但是,在throws子句中调用类是否需要完全细粒度的信息是你需要通过查看程序来决定的。 没有固定的答案。

如果不同的子类型需要不同的处理,那么肯定声明两个不同的exception。 永远不要指望使用您的方法的开发人员猜测您实际上正在抛出不同类型的exception。

如果您声明了两个不同的exception,并且用户从Javadoc知道它们实际上是同一个类的后代,则用户可以选择使用catch (SuperException e)而不是两个单独的catch子句来捕获它们。 但这取决于用户的选择。

如果您不单独声明它们,则IDE不会将相应的@Throws添加到您的Javadoc注释中。 因此,你的Javadoc只会表明你正在抛出SuperException ,这会让用户陷入黑暗。 通过将其放在注释的文本中来解决这个问题并不是一个真正的解决方案。 如果任何工具使用reflection来确定您的方法抛出的内容,它将不会看到从Method.getExceptionTypes()返回的数组中的各个exception。

如果不同exception的预期function或多或少相同,并且只是它们将如何出现在日志中,那么使用父exception和不同的消息可能会更好。