我最近发现雅各布·詹科夫(Jakob Jenkov)关于可充电例外的一篇文章。我非常喜欢这个想法!
我已经做了4年的Java开发人员,我仍然非常恼火,试图弄清楚如何处理第三方库抛出的所有SQLExcepions,IOExceptions和随机异常。我最后考虑了什么时候重新抛出异常,或者将它包装成一个自定义异常,但如果我写了一个自定义异常,那么我该把它放进去吗?在与我正在编写的类相同的包中,还是在一个中心的“例外”包中?我甚至玩弄了自定义异常内部类,因为它们通常看起来很漂亮。
无论如何,Jenkov的想法在这里概述: http://tutorials.jenkov.com/java-exception-handling/exception-enrichment.html
在他的大纲中使用一个可以丰富的例外看起来对我来说真的很有吸引力,因为它似乎非常轻松地支持我的大多数挫折。但我认为我从未见过它在我使用的任何库中使用过。这有什么理由吗?我缺少这种方法的主要缺陷吗?
简单摘要:
public class AppException extends Exception{
public AppException(String errCode, String context, String userMessage, Throwable t){}
public AppException(String, errCode, String context, String userMessage) {}
public void addInfo(String errCode, String context, String userMessage){}
}
public class MyApp {
public static void main(String [] args) {
MyApp app = new MyApp();
app.start(args[0], args[1]);
}
public void start(String username, String password) {
try {
User user = loginController.login(username, password);
} catch (AppException e) {
if (e.getCode().contains("INCORRECT_PASSWORD")) {
logger.warn(e.toString(), e);
// Prompt user for new password and try again.
} else {
logger.error(e.toString(), e);
}
} catch (Exception e) {
logger.error("Unexpected Exception.", e);
}
}
}
public class LoginController {
public User login(String username, String password) {
try {
if (userDao.checkPassword(username, password)) {
// Build and return the user object.
}
} catch (AppExcption e) {
e.addInfo("LOGIN_FAILED", "LoginController", "Failed to login");
throw e;
}
}
}
public class UserDao {
public boolean checkPassword(String username, String password) {
try {
// Check the password against the DB.
if (passwordIsCorrect) {
return true;
} else {
throw new AppException("INCORRECT_PASSWORD", "UserDao", "Password for user " + username + " is not correct.");
}
} catch (SQLException e) {
throw new AppException("DB_CONNECTION_ERR", "UserDao", "Can't connect to Database", e);
}
}
}
Jenkov的文章中提供了异常类的实际实现。在上面的代码示例中,如果DB无法访问,则错误日志将如下所示:
[LOGIN_FAILED, LogginController], [DB_CONNECTION_ERR, UserDao]
[LOGIN_FAILED, LogginController]: Failed to login
[DB_CONNECTION_ERR, UserDao]: Can't connect to Database
<<SQLException stacktrace here>>
但如果输入的密码不正确,则为:
[LOGIN_FAILED, LogginController], [INCORRECT_PASSWORD, UserDao]
[LOGIN_FAILED, LogginController]: Failed to login
[DB_CONNECTION_ERR, UserDao]: Password for user [passed in username] is not correct.
我可能会为错误代码添加枚举或其他内容,以便更轻松地进行选择性处理,并确保它们实际上是唯一的。但是错误消息给出了一个非常清晰的简明视图,它可以很容易地添加额外的信息,因为错误会使调用堆栈成为可能,以便开发人员能够重新创建错误。
重复我的问题。为什么这个用得更广泛?我缺少这种方法的主要缺陷吗?