如何在java中消除过多的空检查?

如何在java中消除过多的空检查?,java,design-patterns,Java,Design Patterns,假设我有如下代码: Vehicle vehicle = vehicleRepostory.findByIdInitialized(vehicleId); Vehicle vehicle = vehicleRepostory.findByIdInitialized(vehicleId); MyObjectNotFoundException.throwIfNull(vehicle, Vehicle.class, vehicleId); 如果找不到车辆,此方法将返回null。规范说,在这种情况下,

假设我有如下代码:

Vehicle vehicle = vehicleRepostory.findByIdInitialized(vehicleId);
Vehicle vehicle = vehicleRepostory.findByIdInitialized(vehicleId);
MyObjectNotFoundException.throwIfNull(vehicle, Vehicle.class, vehicleId);
如果找不到
车辆
,此方法将返回
null
。规范说,在这种情况下,我必须抛出一个
MyObjectNotFoundException
,因此代码如下所示:

Vehicle vehicle = vehicleRepostory.findByIdInitialized(vehicleId);
Vehicle vehicle = vehicleRepostory.findByIdInitialized(vehicleId);
MyObjectNotFoundException.throwIfNull(vehicle, Vehicle.class, vehicleId);
如果我想摆脱对
throwIfNull
的调用,该怎么办。这不是真正的干燥和一个糟糕的设计选择无论如何。一定有我不知道的设计模式。我在网上搜索,但没有找到任何真正有用的东西

一个简单的解决方案可能是将代码放入我的存储库中,但我使用SpringData,因此它只是一个接口:

public interface VehicleRepository extends Repository<Vehicle, Long>

// ...

@Query("select v from Vehicle v LEFT JOIN FETCH v.technicalData td LEFT JOIN FETCH v.registrationData rd"
    + " where v.vehicleId = ?")
Vehicle findByIdInitialized(Long vehicleId);
公共接口车辆存储库扩展存储库
// ...
@查询(“从车辆中选择v v左连接获取v.technicalData td左连接获取v.registrationData rd”
+“其中v.vehicleId=?”)
车辆findByIdInitialized(长车辆ID);
您可以使用design模式,但最好选择异常IMHO


为了保持干燥,你应该把垃圾放入
findbyidinInitialized

您可以查看Java中的@NotNull注释。它有几种风格,有些在编译时进行验证,有些在运行时进行验证。一些编辑器(如IntelliJ IDEA)可以在您执行可能导致NPE的操作时发出警告


当然,如果您可以重新设计存储库本身以抛出所需的异常,那将是最好的选择。如果没有这一点,您需要修补行为的变通方法

一种方法是反射:将对
repository
的调用包装到一个方法中,该方法将
findbyidinInitialized
作为字符串接收并反射地调用它。然后,该方法可以抛出相应的异常


另一种方法可能是让一些AOP做同样的事情,但可能需要更多的类型安全性。

听起来基本上您希望您的存储库支持这一点:

Vehicle vehicle = vehicleRepository.loadExisting(vehicleId);
其中,
loadExisting
findbyidinInitialized
之间的区别在于前者期望实体存在,如果实体不存在则抛出异常

这样,所有存储库客户端都可以决定在执行查找时是否希望缺少实体导致异常。您甚至可能会发现,所有按ID进行的查找都应该抛出一个异常——在这种情况下,您可以返回到使用单个方法

编辑:如果存储库是自动生成的,我将采用以下三种方法之一:

  • 包起来
  • 扩展它
  • 修改生成器

以下哪种选择最合适取决于具体细节。

我建议您向findByIdInitialized添加一个可为空的参数,如下所示:

Vehicle findByIdInitialized(int vehicleId, boolean throwException) {
   // implementation behavior...

   if (throwException) {
       MyObjectNotFoundException.throwIfNull(vehicle, Vehicle.class, vehicleId);
   }
}
使用以下命令:

import static java.util.Objects.requireNonNull;

.
.
.

Object o = requireNonNull(obj);

听起来你想要“在方法返回后”AOP建议,它截取空值并抛出异常。

不,绝对不是-如果实体找不到,这将是避免抛出异常的一种方法。@JonSkeet,是的,但他询问了可能性,他得到了一个。提出意见和建议。由于某种原因,这种模式存在。在某些情况下,可以期望使用它。我对这个问题的理解是,OP已经承诺要抛出一个异常,但他想改变这样做的方式。编辑第二段后,您的答案更有意义,但第一部分对这个问题没有帮助。我说过规范明确规定我必须抛出一个异常。@JonSkeet,您的理解是正确的。你的评论可能是指我答案的第一个版本。NVM感谢康姆尼。你好。我编辑了我的问题。我忘了指出存储库是生成的,所以我没有一个具体的类可以修改。@AdamArold:它是由什么生成的,您不能更改生成过程或包装它吗?我使用SpringData来实现这一点。我只需要扩展存储库,其余的由Spring负责。也许我可以修改Spring配置中声明的工厂bean:
好的,这会让我继续。顺便说一句,自从你回答了我的问题以来,今天是值得纪念的一天