Java POJO是否应该具有字段验证并在setter方法中引发异常?

2022-09-02 21:38:16

假设我们有数十个java POJO,它们代表我的领域,也就是说,我在系统中的数据作为对象在系统的不同层之间流动。系统可以是 Web 应用程序,也可以是简单的桌面应用程序。域由什么组成并不重要。

在设计我的系统时,我对应该将任何验证逻辑放在哪里感到困惑。我的POJO(域对象)表示我的数据,这些对象中的一些字段必须遵守某些标准,但是如果我在我的setter-method中放置了很多验证逻辑,那么告诉调用客户端的唯一方法是抛出一个异常。如果我不希望系统崩溃,则异常必须是必须捕获和处理的已检查异常。这样做的结果是,每次我使用 setter-methods(甚至构造函数)创建新对象时,我都会重新引发该异常或使用 try-catch 块。被迫在许多 setter-method 上使用 try-catch 是不对的。

所以问题是我应该把我的验证逻辑放在哪里,这样我就不会用大量的样板试听块和重写来混淆我的代码。欢迎最优秀的 JAVA 字节食客加入讨论。

我已经研究和谷歌搜索,但没有找到任何关于这个话题的具体讨论,所以我以极大的热情等待着更深入地了解事情真正应该如何做。


答案 1

当你说

这些对象内部的某些字段必须符合某些标准

它总是有助于考虑系统中的不变量,即你不惜一切代价维护的东西或必须始终遵循的规则。
您的POJO是数据对象上此类不变量的“最后一道防线”,因此是放置验证逻辑的适当(甚至必要)位置。如果没有此类验证,对象可能不再表示在您的域中有意义的内容。

这些系统不变量在您的对象(或方法)与其“客户端”之间形成契约。如果有人试图违反(希望有据可查的)合同使用它们,那么抛出异常是正确的做法,因为客户有责任正确使用系统的各个部分。

随着时间的流逝,对于任何违反合同的情况,我开始倾向于未经检查的异常而不是检查的异常,部分原因是您提到的原因,即避免 - 到处都是阻塞。
Java的标准未经检查的异常包括:trycatch

  • NullPointerException
  • 非法争议异常
  • 非法状态异常
  • 不支持的操作异常

最佳做法准则是在错误被视为可恢复时使用已检查的异常,否则使用未检查的异常

Joshua Bloch的“Effective Java,第2版”的第9章提供了更多关于这个主题的智慧:

  • 项目57:仅对异常情况使用例外
  • 项目 58:对可恢复条件使用已检查的异常,对编程错误使用运行时异常
  • 项目 59:避免不必要地使用已检查的异常
  • 第60项:赞成使用标准例外

上述任何一项都不应阻止您在较高级别使用任何适当的验证逻辑,尤其是强制实施任何特定于上下文的业务规则或约束。


答案 2

总而言之,我也不认为有一个独特的解决方案可以满足各种需求,它只是归结为你的场景和偏好。

从封装的角度来看,我相信设置者验证是正确的方法,因为它是决定所提供的信息是否正确并提供可能错误的详细解释的合乎逻辑的地方。但是,我不确定您所说的是什么意思:

如果我不希望系统崩溃,则异常必须是已检查的异常...

为什么系统会崩溃?未检查的异常可以像选中的异常一样很好地捕获。您需要弄清楚当此类事件发生时程序应如何运行,以便您可以决定从何处捕获它们以及执行哪些操作。

检查与未检查长期以来一直以各种方式和信念进行辩论,但我看不出你有什么理由不抛出一个不受检查的例外。只需制作一个常见的(或使用已经存在的)或任何漂浮在你的船上的东西,相应地标记你的方法签名,并添加适当的java-docs,这样任何调用它们的人都知道会发生什么,并在需要时扔掉它。ConfigurationExceptionIllegalArgumentException

根据您的对象关系和层次结构,另一个解决方案可能是一些构建器,它们仅在创建实例时运行自定义验证。但就像我说的,这实际上取决于场景,你可能无法阻止其他人手动实例化和错误地填充某些对象。