三目运算符报NPE了!!!??
第一次遇到的时候,年幼无知的我,觉得明明就是很简单的一行代码,怎么会报错,百思不得其解。
模拟问题代码
public class Test {
private Long money;
public Long getMoney() {
return money;
}
public void setMoney(Long money) {
this.money = money;
}
public static void main(String[] args) {
Test test = new Test();
Long money = Objects.nonNull(test) ? test.getMoney() : 0L;
System.out.println(money);
}
}
输出结果
Exception in thread "main" java.lang.NullPointerException
at com.gree.invoice.b2c.test.Test.main(Test.java:26)
Process finished with exit code 1
怎么让代码不报错
三种方法返回结果不一样,根据实际场景选择使用。
方法一:使用Long.valueOf()
,输出结果为null。
// 输出结果 null
Long money = Objects.nonNull(test) ? test.getMoney() : Long.valueOf(0L);
方法二:对money字段进行判空,输出结果为0。
// 输出结果 0
Long money = Objects.nonNull(test) && Objects.nonNull(test.getMoney()) ? test.getMoney() : 0L;
方法三:Java8还可以使用Optional判空。
// 输出结果 0
Long money = Optional.ofNullable(test).map(Test::getMoney).orElse(0L);
// 输出结果 null
Long money = Optional.ofNullable(test).map(Test::getMoney).orElse(null);
原因解析
参考:《新版阿里巴巴Java开发手册》提到的三目运算符的空指针问题到底是个怎么回事?
Long money = Objects.nonNull(test) ? test.getMoney() : 0L;
因为三目运算符的第二,第三位操作数分别为包装类对象和基本数据类型时,编译器会对包装类自动进行拆箱操作。
在上面的表达式中,0L
为基本数据类型long
,test.getMoney()
为包装类Long
,且Long money
要求返回值为包装类,所以实际运行的代码为:Long money = Long.valueOf(Objects.nonNull(test) ? test.getMoney().longValue() : 0L);
由实际运行的代码可知,test.getMoney()
为null,test.getMoney().longValue()
也就是null.longValue()就会导致NPE。
其实,《阿里巴巴Java开发手册(泰山版)》中也有提及:
编码好习惯
那么平时怎么避免这种问题呢?
那就是保持三目运算符的第二位和第三位表达式的类型一致,最后要做好单元测试。
这也就是为什么改成Long money = Objects.nonNull(test) ? test.getMoney() : Long.valueOf(0L);
不会再报错的原因了。