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



我需要检查某个值是否为空。如果它不为空,那么只需将一些变量设置为 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.
}

不,在 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应该检查的全部内容。

您可以在此处使用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();

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

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

这假设验证在使用您所在国家/地区的任何地方都是相同的,但通常情况就是如此。如果不是,该方法应命名为 hasStudent(),但这不太通用,并且您冒着在国家/地区复制整个学校界面的风险。例如,在另一个地方,您可能需要hasTeacher()或hasCourse()。

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

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;
}

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

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

作为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;
}

Java 没有"null-safe"操作,例如 Kotlin 的 null safety

您可以:

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

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

你也可以看看vavr的Option,正如下面的帖子所描述的,它比Java的Optional更好,并且具有更丰富的API。

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

相关内容

  • 没有找到相关文章

最新更新