简体   繁体   English

用Java抛出检查异常

[英]Throwing checked exception in Java

Let's say I am designing an API for storing passwords. 假设我正在设计一个用于存储密码的API。 According to Effective Java it is a good idea to use throw clauses to show checked exceptions, however by having a throw clause that throws a SQLException, which is a checked exception, then I am revealing the underlying implementation details of my API and thus I will be unable to change the implementation details of my API at a later stage. 根据Effective Java,使用throw子句显示已检查的异常是一个好主意,但是,通过具有抛出SQLException的throw子句(这是一个已检查的异常),那么我将揭示API的基本实现细节,因此,我将稍后无法更改我的API的实现详细信息。 One of the pros to throwing a checked exception is that the programmer who uses the API should be able to handle the exception in a manner of their choosing. 引发检查异常的优点之一是,使用API​​的程序员应能够以自己选择的方式处理异常。 Which of these two methods should I choose to do, add a throw clause which reveals the implementation or hide it or use a different approach? 我应该选择这两种方法中的哪一种,添加一个throw子句以显示实现或将其隐藏或使用其他方法?

Your motivation is correct for not "leaking" SQLException to the users of your class. 您的动机是正确的,因为没有向类的用户“泄漏” SQLException

The fact that you're using SQL could be considered an implementation detail. 您正在使用SQL的事实可以被视为实现细节。 You may even swap SQL persistence for say, an in-memory one at a later time, and this change shouldn't impact the users of your class. 您甚至可以稍后将SQL持久性换成一个内存中的持久性,并且此更改不应影响您的类的用户。

If you are inclined to use checked exceptions, I would define your own exception type (say, PasswordStoreException -- just an example name). 如果您倾向于使用检查的异常,则可以定义自己的异常类型(例如, PasswordStoreException仅作为示例名称)。 You can use it to wrap the original exception that was thrown, eg: 您可以使用它包装引发的原始异常,例如:

try {
   // do whatever
} catch (SQLException ex) {
   throw new PasswordStoreException(ex);
}
  1. It is today considered bad design for an API to declare checked exceptions. 今天,API声明已检查的异常被认为是错误的设计。 If you have ever used such an API, you should already know why. 如果您曾经使用过这样的API,则应该已经知道原因。
  2. In any case your API should never throw (let alone declare ) exceptions belonging to other APIs. 在任何情况下,您的API都绝对不能抛出(更不用说声明 )属于其他API的异常。 If you do that, you hang a completely unrelated dependency on your client's back. 如果这样做,您将完全不相关的依赖项挂在客户的背上。 The only "exception" to this rule are JDK's standard exceptions like NPE, ISE and the like. 该规则的唯一“例外”是JDK的标准例外,例如NPE,ISE等。

Catch the SQLException, and wrap it into your own exception: 捕获SQLException,并将其包装到您自己的异常中:

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

Whether this exception should be a checked exception or a runtime exception depends on what the caller can do about it. 该异常是应检查的异常还是运行时异常,取决于调用方对此的处理方式。 If it's recoverable (which, I think, is not the case here), it should be a checked exception. 如果它是可恢复的(我认为不是这种情况),则应将其作为检查异常。 If it's not recoverable (the caller can just display an error message), then it should be a runtime exception. 如果它是不可恢复的(调用方只能显示一条错误消息),那么它应该是运行时异常。

If it's a checked exception, you have no choice; 如果是检查异常,则别无选择。 the exception MUST be declared in the throws clause of the method. 异常必须在方法的throws子句中声明。

Try this.. 尝试这个..

fillInStackTrace() method is called to re-initialize the stack trace data in the newly created throwable. 调用fillInStackTrace()方法以重新初始化新创建的throwable中的堆栈跟踪数据 Will be helpful in masking the info about the exception when tries to access the API. 尝试访问API时,将有助于掩盖有关异常的信息

As is, it is always a good idea to throw your own exception checked/unchecked. 照原样,将您自己的异常选中/取消选中总是一个好主意。 But before that, try to fix the underlying exception if possible. 但是在此之前,请尝试尽可能修复基础异常。 I always prefer the below way, 我总是喜欢下面的方式,

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

So, 所以,

1) You don't expose the SRQException directly, but you throw your own version of the exception. 1)您不会直接公开SRQException,但是会抛出自己的异常版本。

2) You tried to solve the exception once and if not you alerted somehow - through a mail or a log statement. 2)您尝试解决该异常一次,如果没有解决,则通过邮件或日志语句以某种方式发出警报。

3) Finally, you ve released all the resources if you succeed in solving the exception. 3)最后,如果成功解决了异常,您就释放了所有资源。

The finally clause can be avoided if you use the new Java7's try with resource close option. 如果您使用新的Java7的try with resource close选项,则可以避免finally子句。

For whether to throw checked or unchecked exception, I will give you an example 关于是否引发检查或未检查的异常,我将举一个例子

1) Say an exceptions like NPE - they are programmatic errors and the developer should be more responsible to have not created a NullPointer. 1)说出像NPE这样的异常-它们是程序错误,开发人员应更负责任地创建NullPointer。 You don't expect your code to account for such careless errors and put a try(NPE), catch(NPE). 您不希望您的代码考虑到这样的粗心大意的错误,而是尝试使用try(NPE),catch(NPE)。 So throw a unchecked exceptions. 因此抛出未经检查的异常。

2) On the other hand the exceptions like SQL exceptions are at the rare cases, account for some external dependency. 2)另一方面,像SQL异常这样的异常在极少数情况下会引起一些外部依赖性。 So, better throw a user defined checked exceptions. 因此,最好抛出一个用户定义的检查异常。 And the user can determine if he can connect to the backup SQL server if any. 用户可以确定是否可以连接到备用SQL Server。

3) There are another clause of exceptions, where the program cannot continue furhter. 3)还有另一个例外条款,即程序无法继续运行。 Say a Memory Out of Bounds. 说出无限的回忆。 They should be thrown as Errors. 应该将它们作为错误抛出。

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM