我使用x!=null以避免NullPointerException。还有其他选择吗?
if (x != null) {
// ...
}
我使用x!=null以避免NullPointerException。还有其他选择吗?
if (x != null) {
// ...
}
当前回答
Google集合框架为实现空检查提供了一种良好而优雅的方式。
库类中有一个方法如下:
static <T> T checkNotNull(T e) {
if (e == null) {
throw new NullPointerException();
}
return e;
}
用法是(使用import static):
...
void foo(int a, Person p) {
if (checkNotNull(p).getAge() > a) {
...
}
else {
...
}
}
...
或者在您的示例中:
checkNotNull(someobject).doCalc();
其他回答
如果不允许未定义的值:
您可以配置IDE以警告您可能的空取消引用。例如,在Eclipse中,请参阅首选项>Java>编译器>错误/警告/空分析。
如果允许未定义的值:
如果您想定义一个新的API,其中未定义的值是有意义的,请使用OptionPattern(可能在函数语言中很熟悉)。它具有以下优点:
API中明确说明是否存在输入或输出。编译器强制您处理“未定义”的情况。选项是monad,因此不需要进行冗长的空检查,只需使用map/foreach/getOrElse或类似的组合符即可安全地使用该值(示例)。
Java 8内置了可选类(推荐);对于早期版本,有一些库选项,例如Guava的Optional或FunctionalJava的Option。但是,像许多函数样式模式一样,在Java中使用Option(甚至是8)会产生一些样板,您可以使用不那么冗长的JVM语言(例如Scala或Xtend)来减少这些样板。
如果必须处理可能返回null的API,那么在Java中就做不了什么了。Xtend和Groovy有Elvis运算符?:和空安全解引用运算符?。,但请注意,如果引用为null,则返回null,因此它只是“延迟”了对null的正确处理。
问这个问题表明你可能对错误处理策略感兴趣。如何以及在哪里处理错误是一个普遍存在的体系结构问题。有几种方法可以做到这一点。
我最喜欢的是:允许异常在“主循环”或其他具有适当职责的函数中波动-捕获它们。检查错误情况并适当处理它们可以被视为一项专门的责任。
当然,也要看看面向方面编程——它们有很好的方法将if(o==null)handleNull()插入到字节码中。
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()方法中的第二个值(字符串),因为即使有反射(无论如何都不是本文的主题…),也无法轻松检测传入的变量名。
是的,我们知道,在这一行之外,我们将不再遇到空值,因此我们只需安全地调用这些对象上的方法。
这样,代码就干净、易于维护和可读。
我是“快速失败”代码的粉丝。问问你自己——在参数为空的情况下,你在做什么有用的事情吗?如果在这种情况下,您对代码应该做什么没有明确的答案。。。即,它一开始不应该为空,然后忽略它并允许引发NullPointerException。调用代码将与IllegalArgumentException一样具有NPE的意义,但如果抛出NPE,而不是您的代码试图执行一些其他意外的意外逻辑,那么开发人员将更容易调试和理解出了什么问题-这最终会导致应用程序失败。
最终,彻底解决这个问题的唯一方法是使用不同的编程语言:
在Objective-C中,你可以在nil上调用一个方法,而绝对不会发生任何事情。这使大多数空检查变得不必要,但会使错误更难诊断。在Nice这一Java派生语言中,所有类型都有两个版本:可能为空的版本和非空的版本。只能对非空类型调用方法。通过显式检查null,可以将可能为null的类型转换为非null类型。这使得更容易知道哪些地方需要空检查,哪些地方不需要空检查。