我需要检查某些值是否为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.
}
答案 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
你可以:
否则,如果您可以控制域对象,则可以重新设计类,以便从顶级对象获取所需的信息(make Country
类执行所有空检查...)
答案 5 :(得分:0)
您还可以查看vavr的选项,因为下面的帖子描述的比Java的选项更好,并且API更丰富。