特定条件下的异常处理 - 最佳实践

3

我在 DAO 方法中有以下代码:

public void someMethod() throws CustomException {
       try {
           ... do something ...
        }catch(Exception e) {
             if(e.getCause() instanceOf org.hibernate.ConstraintViolationException && e.getMessage().contains("child record found")) {
                  throw new CustomException("Child records found.");
             }else {
                  throw new CustomException("Unable to update.");
             }
        }
}

在服务层:

public void someMethod() throws CustomException {
 dao.someMethod();
}

在控制器中:

public ResponseObject someMethod() {
  ResponseObject response = new ResponseObject();
  try {
    service.someMethod();
    response.setMessage("success");
  }catch(CustomException e) {
    response.setMessage(e.getMessage());
  }
  return response;
}

我是否按照最佳实践正确进行了操作?还有什么可以做来使它更加合适?

非常感谢您的帮助!


“最佳实践”相关问题最好在Code Review上提问。 - Tom Zych
1个回答

1
我注意到几件事情。首先,只有在特殊情况下才使用异常。换句话说,异常应该是例外而不是常态。从看起来的情况来看,“ConstraintViolationException”是一个经常出现的东西。 异常使代码变得丑陋,难以调试,并减少了JVM优化,这可以极大地加快程序执行速度。
其次,您应该仅在调用者可以合理地期望恢复时使用已检查的异常(不会从RuntimeException扩展)。在您的情况下,调用者除了向客户端提供错误消息之外没有任何恢复操作。 通过抛出已检查的异常,您强制调用者在catch子句中处理异常或向外传播它。(这些陷阱都在Joshua Bloch的优秀书籍“Effective Java”中详细介绍了。)
第三,在您的异常处理中,您尝试解析错误消息。这可能会带来很多问题,因为第三方经常更改其错误消息,因为它们不是API的一部分。一旦发生这种情况,您的代码就会出错。您异常处理中的另一个小问题是将您的JPA实现与Hibernate绑定在一起。如果以后您想要更改为EclipseLink怎么办?
有一种方法可以解决所有这些问题。
在DAO中去掉异常处理。 向DAO添加以下方法:
boolean childRecordExists(Record record)

然后,在您的控制器中,有如下内容:
if (service.childRecordExists()){
   response.setMessage("Failed.  A child record exists");  //a useful error message for the user, as you know *exactly* why failure happened
} else {
    service.someMethod();
    response.setMessage("Success");
}

你需要在控制器中添加某种异常处理程序。(如果你正在使用Spring MVC,你可以使用ExceptionHandler注释将其作为另一种方法添加。) 这将解决真正的异常情况(对于日常用户体验来说是异常情况,用户无法修复的问题)。


OP特别提到了Spring - 所有的Spring异常都是未经检查的。而且,默认情况下,Spring的事务层使用未经检查的异常来决定回滚事务。我不确定在这种情况下不使用未经检查的异常是否恰当。 - Serge Ballesta

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接