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