Java:避免在嵌套类中检查null(深度空检查)

lla*_*all 34 java null class ternary

想象一下,我有一个班级家庭.它包含一个人员列表.每个(类)Person包含一个(类)地址.每个(类)地址包含一个(类)PostalCode.任何"中间"类都可以为null.

那么,有没有一种简单的方法来获取PostalCode,而不必在每一步检查null?即,有没有办法避免以下菊花链代码?我知道没有"原生"Java解决方案,但希望有人知道库或其他东西.(已检查Commons&Guava并没有看到任何内容)

if(family != null) {
    if(family.getPeople() != null) {
        if(family.people.get(0) != null) {
            if(people.get(0).getAddress() != null) {
                if(people.get(0).getAddress().getPostalCode() != null) {
                    //FINALLY MADE IT TO DO SOMETHING!!!
                }
            }
        }
    }
}
Run Code Online (Sandbox Code Playgroud)

不,不能改变结构.它来自我无法控制的服务.

不,我不能使用Groovy,它是方便的"猫王"操作员.

不,我宁愿不等待Java 8:D

我不敢相信我是第一个生病的人,厌倦了写这样的代码,但我找不到解决办法.

想法?

谢谢

-
llappall

小智 18

您可以用于:

product.getLatestVersion().getProductData().getTradeItem().getInformationProviderOfTradeItem().getGln();
Run Code Online (Sandbox Code Playgroud)

可选等效项:

Optional.ofNullable(product).map(
            Product::getLatestVersion
        ).map(
            ProductVersion::getProductData
        ).map(
            ProductData::getTradeItem
        ).map(
            TradeItemType::getInformationProviderOfTradeItem
        ).map(
            PartyInRoleType::getGln
        ).orElse(null);
Run Code Online (Sandbox Code Playgroud)

  • @Anirudh 在这种情况下,映射器是方法引用并且永远不会为空。映射器返回的值可以为 null,在这种情况下,映射返回Optional.empty() (2认同)

ami*_*mit 14

您的代码行为与...相同

if(family != null &&
  family.getPeople() != null &&
  family.people.get(0) != null && 
  family.people.get(0).getAddress() != null &&
  family.people.get(0).getAddress().getPostalCode() != null) { 
       //My Code
}
Run Code Online (Sandbox Code Playgroud)

由于短路评估,这也是安全的,因为如果第一个是假的,第二个条件将不会被评估,如果第二个是假的,第三个条件将不会被评估,......并且你将不会获得NPE,因为如果它.


Ami*_*pta 10

如果您使用的是 java8,那么您可以使用;

resolve(() -> people.get(0).getAddress().getPostalCode());
    .ifPresent(System.out::println);

:
public static <T> Optional<T> resolve(Supplier<T> resolver) {
    try {
        T result = resolver.get();
        return Optional.ofNullable(result);
    }
    catch (NullPointerException e) {
        return Optional.empty();
    }
}
Run Code Online (Sandbox Code Playgroud)

参考:避免空检查

  • 该解决方案依赖于捕获 NPE,而 NPE 的性能会非常差。 (2认同)

Pau*_*lin 6

你可以得到的最接近的是利用条件中的捷径规则:

if(family != null && family.getPeople() != null && family.people.get(0) != null  && family.people.get(0).getAddress() != null && family.people.get(0).getAddress().getPostalCode() != null) {
                    //FINALLY MADE IT TO DO SOMETHING!!!

}
Run Code Online (Sandbox Code Playgroud)

顺便说一句,捕捉异常而不是提前测试条件是一个可怕的想法.


小智 5

您可以通过利用 Java 8 可选类型来摆脱所有这些 null 检查。

流方法 - map()接受 Function 类型的 lambda 表达式,并自动将每个函数结果包装到Optional 中。这使我们能够连续传输多个映射操作。空检查会在底层自动处理。

Optional.of(new Outer())
  .map(Outer::getNested)
  .map(Nested::getInner)
  .map(Inner::getFoo)
  .ifPresent(System.out::println);
Run Code Online (Sandbox Code Playgroud)

我们还有另一种选择来实现相同的行为,即利用供应商函数来解析嵌套路径:

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

如何调用新方法?往下看:

Outer obj = new Outer();
obj.setNested(new Nested());
obj.getNested().setInner(new Inner());

resolve(() -> obj.getNested().getInner().getFoo())
    .ifPresent(System.out::println);
Run Code Online (Sandbox Code Playgroud)


MBy*_*ByD 0

这不是一个很酷的想法,但是捕获异常怎么样:

    try 
    {
        PostalCode pc = people.get(0).getAddress().getPostalCode();
    }
    catch(NullPointerException ex)
    {
        System.out.println("Gotcha");
    }
Run Code Online (Sandbox Code Playgroud)