我使用x!=null以避免NullPointerException。还有其他选择吗?
if (x != null) {
// ...
}
我使用x!=null以避免NullPointerException。还有其他选择吗?
if (x != null) {
// ...
}
当前回答
函数方法可能有助于包装重复的空检查并执行匿名代码,如下面的示例。
BiConsumer<Object, Consumer<Object>> consumeIfPresent = (s,f) ->{
if(s!=null) {
f.accept(s);
}
};
consumeIfPresent.accept(null, (s)-> System.out.println(s) );
consumeIfPresent.accept("test", (s)-> System.out.println(s));
BiFunction<Object, Function<Object,Object>,Object> executeIfPresent = (a,b) ->{
if(a!=null) {
return b.apply(a);
}
return null;
};
executeIfPresent.apply(null, (s)-> {System.out.println(s);return s;} );
executeIfPresent.apply("test", (s)-> {System.out.println(s);return s;} );
其他回答
只是永远不要使用null。不要允许。
在我的类中,大多数字段和局部变量都有非空的默认值,我在代码中的任何地方都添加了契约语句(总是在断言上),以确保这是强制执行的(因为它比让它作为NPE出现然后必须解析行号等更简洁、更具表达力)。
一旦我采用了这种做法,我注意到问题似乎会自行解决。你会在开发过程中很早就发现事情,只是偶然发现自己有一个弱点。。更重要的是。。它有助于封装不同模块的关注点,不同模块可以相互“信任”,不再在代码中添加if=nullelse结构!
这是一种防御性编程,从长远来看,代码会更加干净。始终对数据进行净化,例如在这里通过强制执行严格的标准,问题就会消失。
class C {
private final MyType mustBeSet;
public C(MyType mything) {
mustBeSet=Contract.notNull(mything);
}
private String name = "<unknown>";
public void setName(String s) {
name = Contract.notNull(s);
}
}
class Contract {
public static <T> T notNull(T t) { if (t == null) { throw new ContractException("argument must be non-null"); return t; }
}
合同就像是小型单元测试,即使在生产中也始终在运行,当事情失败时,你知道原因,而不是随机的NPE,你必须设法弄清楚。
根据所检查的对象类型,您可以使用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");
您还可以使用CheckerFramework(带有JDK7及更高版本)静态检查空值。这可能会解决很多问题,但需要运行一个目前仅适用于OpenJDK AFAIK的额外工具。https://checkerframework.org/
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。
切勿将变量初始化为空。如果(1)不可能,则将所有集合和数组初始化为空集合/数组。
在您自己的代码中执行此操作,您可以避免!=空检查。
大多数时候,空检查似乎保护了集合或数组上的循环,所以只要将它们初始化为空,就不需要任何空检查。
// Bad
ArrayList<String> lemmings;
String[] names;
void checkLemmings() {
if (lemmings != null) for(lemming: lemmings) {
// do something
}
}
// Good
ArrayList<String> lemmings = new ArrayList<String>();
String[] names = {};
void checkLemmings() {
for(lemming: lemmings) {
// do something
}
}
这是一个很小的开销,但它值得更干净的代码和更少的NullPointerExceptions。