我使用x!=null以避免NullPointerException。还有其他选择吗?
if (x != null) {
// ...
}
我使用x!=null以避免NullPointerException。还有其他选择吗?
if (x != null) {
// ...
}
当前回答
我尝试过NullObjectPattern,但对我来说并不总是最好的方法。有时,“不采取行动”并不合适。
NullPointerException是一个运行时异常,这意味着它是开发人员的错,并且凭借足够的经验,它会准确地告诉您错误在哪里。
现在来回答:
尽量将所有属性及其访问器设为私有,或者避免将它们暴露给客户端。当然,您可以在构造函数中设置参数值,但通过缩小范围,您不会让客户端类传递无效值。如果需要修改值,可以始终创建新对象。您只检查构造函数中的值一次,在其他方法中,您几乎可以确定这些值不为空。
当然,经验是理解和应用这一建议的更好方式。
字节
其他回答
我高度无视建议在任何情况下使用空对象的答案。这种模式可能会破坏合同,将问题埋得越来越深,而不是解决问题,更不用说使用不当会产生另一堆需要未来维护的样板代码。
实际上,如果从方法返回的某个值可以为空,并且调用代码必须对此做出决定,那么应该有一个更早的调用来确保状态。
还请记住,如果不小心使用,空对象模式将占用内存。为此,NullObject的实例应该在所有者之间共享,而不是每个所有者的unigue实例。
此外,我不建议在类型是原始类型表示的情况下使用这种模式,比如数学实体,它们不是标量:向量、矩阵、复数和POD(普通旧数据)对象,它们是用来以Java内置类型的形式保存状态的。在后一种情况下,您将以任意结果调用getter方法。例如,NullPerson.getName()方法应该返回什么?
为了避免荒谬的结果,值得考虑这样的案例。
我可以更笼统地回答吗!
当方法以我们不期望的方式获取参数时,我们通常会遇到这个问题(错误的方法调用是程序员的错误)。例如:您希望得到一个对象,而得到一个null。您希望得到一个至少包含一个字符的字符串,而得到一个空字符串。。。
因此:
if(object == null){
//you called my method badly!
}
or
if(str.length() == 0){
//you called my method badly again!
}
他们都希望在执行任何其他函数之前确保我们收到了有效的参数。
如其他一些答案中所述,为了避免上述问题,您可以遵循契约设计模式。请参见http://en.wikipedia.org/wiki/Design_by_contract.
要在java中实现这种模式,可以使用javax.annotation.NotNull等核心java注释,或者使用Hibernate Validator等更复杂的库。
只是一个示例:
getCustomerAccounts(@NotEmpty String customerId,@Size(min = 1) String accountType)
现在,您可以安全地开发方法的核心函数,而无需检查输入参数,它们可以保护您的方法不受意外参数的影响。
您可以更进一步,确保在应用程序中只能创建有效的pojo。(来自hibernate验证器站点的示例)
public class Car {
@NotNull
private String manufacturer;
@NotNull
@Size(min = 2, max = 14)
private String licensePlate;
@Min(2)
private int seatCount;
// ...
}
在Java中避免空检查的最佳方法是正确处理和使用异常。在我的经验中,随着您向前端移动,空检查变得越来越常见和必要,因为它更接近于通过UI提供无效信息的用户(例如,没有值,为字段提交)。
有人可能会争辩说,你应该能够控制UI正在做什么,以免你忘记大多数UI是通过某种类型的第三方库完成的,例如,根据情况或库的不同,它可能会为空白文本框返回NULL或空字符串。
您可以这样组合这两者:
try
{
myvar = get_user_supplied_value();
if (myvar == null || myvar.length() == 0) { alert_the_user_somehow(); return; };
process_user_input(myvar);
} catch (Exception ex) {
handle_exception(ex);
}
人们采取的另一种方法是:
if (myvar && myvar.length() > 0) { };
你也可以抛出一个异常(这是我更喜欢的)
if (myvar == null || myvar.length() == 0) {
throw new Exception("You must supply a name!");
};
但这取决于你。
Java8带来了新的Java.util.Optional类,它可以解决一些问题。至少可以说,它提高了代码的可读性,并且在公共API的情况下,使API的契约对客户端开发人员更加清晰。
它们是这样工作的:
给定类型(Fruit)的可选对象被创建为方法的返回类型。它可以是空的或包含Fruit对象:
public static Optional<Fruit> find(String name, List<Fruit> fruits) {
for (Fruit fruit : fruits) {
if (fruit.getName().equals(name)) {
return Optional.of(fruit);
}
}
return Optional.empty();
}
现在看看这段代码,我们在其中搜索给定Fruit实例的Fruit(水果)列表:
Optional<Fruit> found = find("lemon", fruits);
if (found.isPresent()) {
Fruit fruit = found.get();
String name = fruit.getName();
}
您可以使用map()运算符对可选对象执行计算,或从中提取值。orElse()允许您为缺少的值提供回退。
String nameOrNull = find("lemon", fruits)
.map(f -> f.getName())
.orElse("empty-name");
当然,检查空/空值仍然是必要的,但至少开发人员意识到该值可能是空的,忘记检查的风险是有限的。
在从头开始使用Optional构建的API中,只要返回值可能为空,并且仅在不能为空时返回纯对象(惯例),客户端代码可能会放弃对简单对象返回值的空检查。。。
当然,Optional也可以用作方法参数,在某些情况下,可能比5或10个重载方法更好地指示可选参数。
可选提供了其他方便的方法,例如允许使用默认值的orElse,以及与lambda表达式一起使用的ifPresent。
我邀请您阅读这篇文章(我撰写这个答案的主要来源),其中很好地解释了NullPointerException(以及一般的空指针)问题以及Optional带来的(部分)解决方案:Java Optional Objects。
根据所检查的对象类型,您可以使用apachecommons中的一些类,例如:apachecommons-lang和apachecommons集合
例子:
String foo;
...
if( StringUtils.isBlank( foo ) ) {
///do something
}
或(取决于您需要检查的内容):
String foo;
...
if( StringUtils.isEmpty( foo ) ) {
///do something
}
StringUtils类只是众多类中的一个;在commons中有相当多的好类可以进行空安全操作。
下面是一个示例,说明当您包含apache库(commons-lang-2.4.jar)时,如何在JAVA中使用空值验证
public DOCUMENT read(String xml, ValidationEventHandler validationEventHandler) {
Validate.notNull(validationEventHandler,"ValidationHandler not Injected");
return read(new StringReader(xml), true, validationEventHandler);
}
如果您使用的是Spring,Spring的包中也有相同的功能,请参见库(Spring-2.46.jar)
关于如何使用spring中的静态类f的示例(org.springframework.util.Assert)
Assert.notNull(validationEventHandler,"ValidationHandler not Injected");