如何避免在方法链中检查空值?

时间:2018-03-20 09:06:50

标签: java exception-handling nullpointerexception

我需要检查某些值是否为null。如果它不为null,那么只需将一些变量设置为true即可。这里没有其他声明。我得到了太多像这样的条件检查。

有没有办法处理这个空检查而不检查所有方法返回值?

if(country != null && country.getCity() != null && country.getCity().getSchool() != null && country.getCity().getSchool().getStudent() != null .....) {
    isValid = true;
}

我想直接检查变量并忽略NullpointerException。这是一个好习惯吗?

try{
    if(country.getCity().getSchool().getStudent().getInfo().... != null)
} catch(NullPointerException ex){
    //dont do anything.
}

6 个答案:

答案 0 :(得分:63)

不,在Java中捕获NPE而不是对引用进行空值检查通常不是一种好习惯。

如果您愿意,可以使用Optional进行此类操作:

if (Optional.ofNullable(country)
            .map(Country::getCity)
            .map(City::getSchool)
            .map(School::getStudent)
            .isPresent()) {
    isValid = true;
}

或只是

boolean isValid = Optional.ofNullable(country)
                          .map(Country::getCity)
                          .map(City::getSchool)
                          .map(School::getStudent)
                          .isPresent();

如果那是isValid应该检查的全部内容。

答案 1 :(得分:15)

您可以在此处使用Optional,但会在每一步创建一个Optional对象。

boolean isValid = Optional.ofNullable(country)
    .map(country -> country.getCity()) //Or use method reference Country::getCity
    .map(city -> city.getSchool())
    .map(school -> school.getStudent())
    .map(student -> true)
    .orElse(false);

//OR
boolean isValid = Optional.ofNullable(country)
                      .map(..)
                      ....
                      .isPresent();

答案 2 :(得分:7)

面向对象的方法是将isValid方法放在Country和其他类中。它不会减少空检查的数量,但每种方法只有一个,你不会重复它们。

public boolean isValid() {
  return city != null && city.isValid();
}

这假设在您的国家/地区使用的地方验证是相同的,但通常就是这种情况。如果没有,该方法应命名为hasStudent(),但这不太通用,您可能会在Country中复制整个School界面。例如,在另一个地方,您可能需要hasTeacher()或hasCourse()。

另一种方法是使用null对象:

public class Country {
  public static final Country NO_COUNTRY = new Country();

  private City city = City.NO_CITY;

  // etc.
}

我不确定这种情况是否更可取(严格来说你需要一个子类来覆盖所有修改方法),Java 8的方法是在其他答案中使用Optional作为方法,但是我会建议更充分地接受它:

private Optional<City> city = Optional.ofNullable(city);

public Optional<City> getCity() {
   return city;
}

对于null对象和Nullable,只有在始终使用它们而不是null时才会工作(注意字段初始化),否则您仍然需要空检查。所以这个选项避免了null,但你的代码变得更加冗长,以减少其他地方的空值检查。

当然,正确的设计可能是尽可能使用集合(而不是可选)。一个国家有一套城市,城市有一套学校,有一组学生等。

答案 3 :(得分:5)

作为Optional的其他精细用法的替代方法,我们也可以使用带有Supplier<Object> var-args作为参数的实用方法。
这是有道理的,因为我们在对象中没有多个嵌套级别来检查,但需要检查许多字段 此外,它可以很容易地修改为在检测到null时记录/处理某些内容。

    boolean isValid = isValid(() -> address, // first level
                              () -> address.getCity(),   // second level
                              () -> address.getCountry(),// second level
                              () -> address.getStreet(), // second level
                              () -> address.getZip(),    // second level
                              () -> address.getCountry() // third level
                                           .getISO()


@SafeVarargs
public static boolean isValid(Supplier<Object>... suppliers) {
    for (Supplier<Object> supplier : suppliers) {
        if (Objects.isNull(supplier.get())) {
            // log, handle specific thing if required
            return false;
        }
    }
    return true;
}

假设你想添加一些痕迹,你可以写:

boolean isValid = isValid(  Arrays.asList("address", "city", "country",
                                          "street", "zip", "Country ISO"),
                            () -> address, // first level
                            () -> address.getCity(),   // second level
                            () -> address.getCountry(),// second level
                            () -> address.getStreet(), // second level
                            () -> address.getZip(),    // second level
                            () -> address.getCountry() // third level
                                         .getISO()
                         );


@SafeVarargs
public static boolean isValid(List<String> fieldNames, Supplier<Object>... suppliers) {
    if (fieldNames.size() != suppliers.length){
         throw new IllegalArgumentException("...");
    }
    for (int i = 0; i < suppliers.length; i++) {
        if (Objects.isNull(suppliers.get(i).get())) {
            LOGGER.info( fieldNames.get(i) + " is null");
            return false;
        }
    }
    return true;
}

答案 4 :(得分:4)

Java没有“null-safe”操作,例如Kotlin's null safety

你可以:

  • 抓住NPE并忽略它
  • 手动检查所有参考文件
  • 根据其他答案使用可选
  • 使用某种工具,如XLST

否则,如果您可以控制域对象,则可以重新设计类,以便从顶级对象获取所需的信息(make Country类执行所有空检查...)

答案 5 :(得分:0)

您还可以查看vavr的选项,因为下面的帖子描述的比Java的选项更好,并且API更丰富。

https://softwaremill.com/do-we-have-better-option-here/