异常丰富是一种可行的模式吗?

gri*_*gon 7 java error-handling

我最近看到 Jakob Jenkov 写的一篇关于丰富异常的文章。我真的很喜欢这个主意!

我已经成为一名 Java 开发人员 4 年了,但我仍然对试图弄清楚如何处理第三方库抛出的所有 SQLExcepions、IOException 和随机异常感到非常恼火。我最终花了很多心思思考何时合适重新抛出异常,或者将其包装为自定义异常,但如果我编写自定义异常,那么我应该放置它吗?与我正在编写的类在同一个包中,还是在中央“例外”包中?我什至尝试过将自定义异常声明为内部类,因为它们通常看起来非常一次性。

无论如何,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);
        }
    }
}
Run Code Online (Sandbox Code Playgroud)

Jenkov 的文章中提供了异常类的实际实现。在上面的代码示例中,如果数据库无法访问,错误日志将如下所示:

[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>>
Run Code Online (Sandbox Code Playgroud)

但如果输入了错误的密码,则会出现:

[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.
Run Code Online (Sandbox Code Playgroud)

我可能会为错误代码添加一个枚举或其他内容,以使选择性处理更容易,并确保它们实际上是唯一的。但是错误消息给出了错误时的非常清晰简洁的视图,并且很容易在错误出现在调用堆栈中时添加附加信息,以便开发人员能够重新创建错误。

所以重复我的问题。为什么这种方法没有得到更广泛的应用?我所遗漏的这种方法是否存在重大缺陷?