1

假设我正在设计一个用于存储密码的 API。根据 Effective Java,使用 throw 子句来显示检查的异常是一个好主意,但是通过使用 throw 子句抛出 SQLException(这是一个检查的异常),然后我将揭示我的 API 的底层实现细节,因此我将无法在以后更改我的 API 的实现细节。抛出已检查异常的优点之一是使用 API 的程序员应该能够以他们选择的方式处理异常。我应该选择这两种方法中的哪一种,添加一个显示实现的 throw 子句或隐藏它或使用不同的方法?

4

5 回答 5

8

您的动机是正确的,因为您没有“泄露”SQLException给您班级的用户。

您使用 SQL 的事实可以被视为实现细节。您甚至可以稍后将 SQL 持久性替换为内存中的持久性,并且此更改不应影响您班级的用户。

如果您倾向于使用已检查的异常,我会定义您自己的异常类型(例如,PasswordStoreException只是一个示例名称)。您可以使用它来包装引发的原始异常,例如:

try {
   // do whatever
} catch (SQLException ex) {
   throw new PasswordStoreException(ex);
}
于 2012-07-15T09:29:04.277 回答
3
  1. 今天,API 声明检查异常被认为是糟糕的设计。如果你曾经使用过这样的 API,你应该已经知道为什么了。
  2. 在任何情况下,您的 API 都不应该抛出(更不用说声明)属于其他 API 的异常。如果你这样做了,你就会把完全不相关的依赖挂在你客户的背上。此规则的唯一“例外”是 JDK 的标准例外,如 NPE、ISE 等。
于 2012-07-15T11:51:01.237 回答
2

捕获 SQLException,并将其包装到您自己的异常中:

try {
    // JDBC code
}
catch (SQLException e) {
    throw new MyException("Error persisting the secret", e); // choose a better name, of course
}

这个异常应该是检查异常还是运行时异常取决于调用者可以做些什么。如果它是可恢复的(我认为这里不是这种情况),它应该是一个检查异常。如果它不可恢复(调用者只能显示一条错误消息),那么它应该是运行时异常。

如果是受检异常,你别无选择;异常必须在throws方法的子句中声明。

于 2012-07-15T09:29:14.130 回答
1

试试这个..

fillInStackTrace()调用方法来重新初始化新创建的 throwable 中的堆栈跟踪数据。将有助于在尝试访问 API 时屏蔽有关异常的信息。

于 2012-07-15T10:49:35.683 回答
1

照原样,抛出您自己的异常检查/未检查总是一个好主意。但在此之前,如果可能,请尝试修复底层异常。我总是喜欢下面的方式,

try {
    // JDBC code
}
catch (SQLException e) {
    // try to solve the exception at API level
    bollean solvable = trySolveException(e);
    if (!solvable) {
        // Alert the admin, or log the error statement for further debugging.
        mailClient.sendMailToDBAdmin("Some issue storing password", e); 
        // or
        LOG.severe("some issue in storing password " + e.toString);
        throw MyException("A request/logstatement is logged on your behalf regarding the exception", e);
    }
    LOG.info("The exception is solved");
}
finally {
    // don't forget to free your resources - to avoid garbage and memory leaks, incase you have solved the issue in trySolveException(e).
}

所以,

1)您不直接公开 SRQException,而是抛出您自己版本的异常。

2)您尝试解决异常一次,如果没有,您会以某种方式发出警报 - 通过邮件或日志语句。

3) 最后,如果你成功解决了异常,你已经释放了所有的资源。

如果使用新的 Java7 的try with resource close选项,可以避免 finally 子句。

至于是抛出checked还是unchecked异常,我举个例子

1)说一个像NPE这样的异常——它们是程序错误,开发人员应该对没有创建NullPointer负责。您不希望您的代码考虑到这些粗心的错误并放置一个 try(NPE)、catch(NPE)。所以抛出一个未经检查的异常。

2)另一方面,像 SQL 异常这样的异常是在极少数情况下,考虑到一些外部依赖。所以,最好抛出一个用户定义的检查异常。并且用户可以确定他是否可以连接到备份 SQL 服务器(如果有)。

3)还有另一个例外条款,程序无法继续进行。说记忆越界。它们应该作为错误抛出。

于 2012-07-15T10:57:39.343 回答