【发布时间】:2018-10-29 17:18:12
【问题描述】:
一般问题
在编写服务方法时,抛出许多异常与将它们抽象为通用 ServiceException 相比,各有利弊。如果你抛出了很多异常,那么你告诉客户端究竟出了什么问题,以便客户端可以更明智地处理错误。如果您将它们抽象为一个ServiceException(例如通过exception wrapping),那么您就隐藏了问题的详细信息,这在某些情况下可能有用但在其他情况下有害。
例如,通过抛出一个通用的DaoException 来隐藏DAO 类中出错的详细信息可能很有用。这样,客户端就不必知道您是从文件、Web 服务还是关系数据库中读取数据。但是,假设您正在验证用户输入,并且用户输入至少有四件事可能出错。在后一种情况下抛出四个不同的异常不是更明智,每个异常对应一个验证出错的事情吗?
我的具体问题
在我当前的项目中,我正在研究一种将树状结构保存到关系数据库中的服务方法。它必须验证树,并且树至少有四件事可能出错。可能存在重复节点,或者节点可能缺少其必需的 X、Y、Z 字段。因此,服务方法抛出四个不同的异常是有意义的:DuplicateNodeException、MissingXException、MissingYException、MissingZException。
但是服务方法也使用了 DAO 类,它通过 JdbcTemplate 抛出一个DataAccessException。我想知道如何处理这个DataAccessException。将其包装为ManagerException,然后再包装为ServiceException,并将其作为ServiceException 处理是否有意义?然后我将混合(a)抛出特定的描述性异常和(b)抛出通用包装异常的两种方法。在这里混合这些方法是个好主意吗?
我之所以这么问,是因为我觉得捕捉这四个与验证相关的异常有点奇怪,然后又捕捉到一个通用的、不起眼的ServiceException。这似乎很奇怪,因为ServiceException 是如此抽象,以至于乍一看无法判断出了什么问题,您必须检查日志并阅读异常消息,或者导航代码中的调用层次结构。因此,我要求验证混合这两种方法确实是一种好的做法、常见的或明智的做法,因为直觉上这对我来说似乎很奇怪。核心 Java 中是否有任何相似之处,即两种异常处理方法都在同一个方法中使用?
可能的解决方案(根据 Andreas 的回答)
在我的服务类中处理这样的异常有意义吗?下面是一些伪代码,提供了一种可能的解决方案。这样我就不会创建一个无用的、已检查的、无法描述的 ServiceException,但我确实对未检查的异常有一个包罗万象的方法(通过在最后捕获 Exception)。您对此解决方案有何看法?
class HttpService {
private Service service;
// ...
public HttpServiceResponse saveTree(Node root) {
try {
service.saveTree(root);
} catch (DuplicateNodeException e) {
return HttpServiceResponse.failure(DUPLICATE_NODE_EXCEPTION);
} catch (MissingXException e) {
return HttpServiceResponse.failure(MISSING_X_EXCEPTION);
} catch (MissingYException e) {
return HttpServiceResponse.failure(MISSING_Y_EXCEPTION);
} catch (MissingZException e) {
return HttpServiceResponse.failure(MISSING_Z_EXCEPTION);
} catch (Exception e) {
return HttpServiceResponse.failure(INTERNAL_SERVER_ERROR);
}
}
}
【问题讨论】:
-
Effective Java 的建议是抛出适合抽象的异常。
-
@AndyTurner 谢谢,这是个好建议。你投了反对票吗?如果是,为什么?
-
我没有投反对票。
-
虽然 JDBC API 抛出 checked
SQLException,JdbcTemplate包装那些带有 uncheckedDataAccessException的,所以调用者不需要专门申报和处理。无需使用ServiceException包装DataAccessException。如果服务执行其他引发 checked 异常的操作,则应使用特定异常类似地包装这些异常,而不是通用ServiceException。调用者并不关心这些异常,因为调用者对它们无能为力,但不要只是将所有异常包装到一个通用的ServiceException -
@tsolakp 但我希望调用者对它们采取行动,因为它们是可恢复的异常,所以将它们声明为已检查是有意义的,不是吗?请参阅本文末尾的十个技巧:blog.takipi.com/…。
标签: java exception exception-handling