我使用x!=null以避免NullPointerException。还有其他选择吗?
if (x != null) {
// ...
}
我使用x!=null以避免NullPointerException。还有其他选择吗?
if (x != null) {
// ...
}
当前回答
除了使用assert,还可以使用以下命令:
if (someobject == null) {
// Handle null here then move on.
}
这略好于:
if (someobject != null) {
.....
.....
.....
}
其他回答
对于实用程序类,可以检查参数是否为空。
在所有其他情况下,您可能不必这样做。尽可能使用封装,从而减少您想检查null的地方。
我尝试过NullObjectPattern,但对我来说并不总是最好的方法。有时,“不采取行动”并不合适。
NullPointerException是一个运行时异常,这意味着它是开发人员的错,并且凭借足够的经验,它会准确地告诉您错误在哪里。
现在来回答:
尽量将所有属性及其访问器设为私有,或者避免将它们暴露给客户端。当然,您可以在构造函数中设置参数值,但通过缩小范围,您不会让客户端类传递无效值。如果需要修改值,可以始终创建新对象。您只检查构造函数中的值一次,在其他方法中,您几乎可以确定这些值不为空。
当然,经验是理解和应用这一建议的更好方式。
字节
Java中常见的“问题”确实存在。
首先,我的想法是:
我认为,当传递NULL时,如果NULL不是有效值,“吃掉”某些东西是不好的。如果您退出方法时没有出现某种错误,那么这意味着您的方法中没有任何错误,这是不正确的。在这种情况下,您可能会返回null,在接收方法中,您再次检查null,并且它永远不会结束,结果是“if!=null”等。。
因此,IMHO,null必须是阻止进一步执行的关键错误(即,null不是有效值)。
我解决这个问题的方法是:
首先,我遵循以下惯例:
所有公共方法/API始终检查其参数是否为空所有私有方法都不检查null,因为它们是受控制的方法(如果上面没有处理null指针异常,就让它终止)唯一不检查null的其他方法是实用程序方法。他们是公开的,但如果你出于某种原因打电话给他们,你知道你通过了哪些参数。这就像试图在水壶里烧水而不提供水。。。
最后,在代码中,public方法的第一行如下所示:
ValidationUtils.getNullValidator().addParam(plans, "plans").addParam(persons, "persons").validate();
注意,addParam()返回self,这样您就可以添加更多的参数来检查。
如果任何参数为空,方法validate()将抛出checked ValidationException(checked或unchecked更多是设计/品味问题,但我的ValidationException已选中)。
void validate() throws ValidationException;
例如,如果“计划”为空,则消息将包含以下文本:
“参数[plans]遇到非法参数值null”
正如您所看到的,用户消息需要addParam()方法中的第二个值(字符串),因为即使有反射(无论如何都不是本文的主题…),也无法轻松检测传入的变量名。
是的,我们知道,在这一行之外,我们将不再遇到空值,因此我们只需安全地调用这些对象上的方法。
这样,代码就干净、易于维护和可读。
在Java8中,如果局部变量/字段/方法参数/方法返回类型从未赋值为null(并且不检查null),则可以使用类型T;如果可以为null,则可以键入Optional<T>。然后使用方法map处理T->,使用方法flatMap处理T->可选<R>:
class SomeService {
@Inject
private CompanyDao companyDao;
// return Optional<String>
public Optional<String> selectCeoCityByCompanyId0(int companyId) {
return companyDao.selectById(companyId)
.map(Company::getCeo)
.flatMap(Person::getHomeAddress)
.flatMap(Address::getCity);
}
// return String + default value
public String selectCeoCityByCompanyId1(int companyId) {
return companyDao.selectById(companyId)
.map(Company::getCeo)
.flatMap(Person::getHomeAddress)
.flatMap(Address::getCity)
.orElse("UNKNOWN");
}
// return String + exception
public String selectCeoCityByCompanyId2(int companyId) throws NoSuchElementException {
return companyDao.selectById(companyId)
.map(Company::getCeo)
.flatMap(Person::getHomeAddress)
.flatMap(Address::getCity)
.orElseThrow(NoSuchElementException::new);
}
}
interface CompanyDao {
// real situation: no company for such id -> use Optional<Company>
Optional<Company> selectById(int id);
}
class Company {
// company always has ceo -> use Person
Person ceo;
public Person getCeo() {return ceo;}
}
class Person {
// person always has name -> use String
String firstName;
// person can be without address -> use Optional<Address>
Optional<Address> homeAddress = Optional.empty();
public String getFirstName() {return firstName;}
public Optional<Address> getHomeAddress() {return homeAddress;}
}
class Address {
// address always contains country -> use String
String country;
// city field is optional -> use Optional<String>
Optional<String> city = Optional.empty();
String getCountry() {return country;}
Optional<String> getCity() {return city;}
}
您还可以使用CheckerFramework(带有JDK7及更高版本)静态检查空值。这可能会解决很多问题,但需要运行一个目前仅适用于OpenJDK AFAIK的额外工具。https://checkerframework.org/