检查get链中是否有任何对象为null,而不必检查每个深度

Chr*_*örz 7 java java-8 null-check

我正在使用旧版应用程序,在该应用程序中,我经常不得不访问像下面这样嵌套的属性:

a.getB().getC().getD().getE().getF()
Run Code Online (Sandbox Code Playgroud)

问题在于,在任何深度下,该值都可能为空。当然,我可以像这样检查每个深度:

public Optional<F> retrieveValue(A a) {
  if(a != null && a.getB() != null && a.getB().getC() != null && 
     a.getB().getC().getD() != null && 
     a.getB().getC().getD().getE() != null && 
     a.getB().getC().getD().getE().getF() != null) {
    return Optional.of(a.getB().getC().getD().getE().getF());
  } else {
    return Optional.empty();
  }
}

F existingOrCreated = retrieveValue(a).orElse(new F());
Run Code Online (Sandbox Code Playgroud)

但是我必须在许多地方对许多不同的对象执行此操作,因此这些检查会使代码膨胀。大多数情况下,对象不是非null,但是在少数情况下,对象为null。有没有一种更简洁的方法?我正在使用Java 8,但是无法更新提供的旧代码。

Chr*_*örz 8

在回答我的问题之前,我想指出这些链应该首先避免。(检查Demeter定律)。

现在解决问题。因为与Kotlin等其他语言不同,Java 无法提供更简单的空值检查,因此在Java 8之前,您只能选择检查对象的每个级别。

但是由于Java 8提供了作为参数传递的函数,因此我开始使用此功能在Java中构建自己的“安全调用”:

public static <T> Optional<T> retrieveValue(Supplier<T> getter) {
  try {
    return Optional.ofNullable(getter.get());
  } catch (NullPointerException e) {
    return Optional.empty();
  }
}
Run Code Online (Sandbox Code Playgroud)

我们首先来看一下在给定情况下如何调用此方法:

F f = retrieveValue(() -> a.getB().getC().getD().getE().getF()).orElse(new F());
Run Code Online (Sandbox Code Playgroud)

如您所见,我们只是将Supplierto 传递给retrieveValue一个try-catch块,NullPointerExceptionOptional.empty()在可能的情况下调用它,并在这种情况下返回一个。

这种try-catch方法的一个小缺点是,如果NullPointerException在检查过程中发生a,则它比代码中的简单null检查要慢。

这种方法的另一个优点是,该方法可用于任何深度的任何其他空检查,并且不依赖于特定的对象结构。

Node node = retrieveValue(() -> root.getNode().getNode()).orElse(new Node());
Run Code Online (Sandbox Code Playgroud)

  • @AndrewTobilko我明白您的意思了,但是在这种情况下,IMO接上NPE是可以接受的,因为它处于可预期的NPE受控环境中。当然,最好完全不必这样做,但是不必在代码中的任何地方进行这些嵌套的检查就可以使代码膨胀。 (2认同)