java 三段式中包装类报空指针异常的 bug

字数802 大约花费3分钟

目录

  1. 1. 直接使用 null 赋值给三段式
  2. 2. 使用三段式赋值,并且其中一个值是值为 null 的包装类对象
  3. 3. 使用 if 语句而不使用三段式对包装类赋值
  4. 4. 总结

最近在开发中遇到一个莫名其妙的 bug, 一个给 Double 类型赋值的三段式报了空指针异常,从程序字面上完全看不出有什么问题。项目代码,不方便直接贴,我写了下面这段例子进行说明:

直接使用 null 赋值给三段式

1
2
3
4
5
6
7
public static Double test() {
Double b = null;
Double result = b == null
? null
: b.doubleValue();
return result;
}

这段代码能够成功执行,看一下编译后的字节码吧(通过 ItelliJ 查看反编译后的代码)

1
2
3
4
5
public static Double test() {
Object b = null;
Double result = b == null?null:Double.valueOf(((Double)b).doubleValue());
return result;
}

对于三段式中为 double 类型的可选项 b.doubleValue(), 会将 b.doubleValue()进行包装再赋值给 result. 由于另一个可选项是常量 null,所以不会进行拆包。

使用三段式赋值,并且其中一个值是值为 null 的包装类对象

1
2
3
4
5
6
7
8
public static Double test2() {
Double b = null;
Double temp = null;
Double result = b == null
? temp
: b.doubleValue();
return result;
}

给 result 赋值的那句报了空指针异常,这是很奇怪的事,因为按照正常理解,b 为 null 时,直接给将 temp 赋值给 result,result 值变成 null 就好了。

直接看编译后的字节码吧

1
2
3
4
5
6
public static Double test2() {
Object b = null;
Object temp = null;
Double result = Double.valueOf(b == null?((Double)temp).doubleValue():((Double)b).doubleValue());
return result;
}

因为三段式中,一个可选值为 b.doubleValue(),是原始的 double 类型,另一个可选项是变量。编译器就试图先取两个可选值的 double 值,再包装成 Double 类型,由于 temp 内容为 null,报空指针异常了。实际上,如果把 temp 替换成一个返回值为 Double 类型的函数,比如 temp(), 也会进行相同的处理,如果 temp()值为空,也会报空指针异常。另外,如果
b.doubleValue() 改成 double 常量,比如 1d,也是一样的。

使用 if 语句而不使用三段式对包装类赋值

1
2
3
4
5
6
7
8
9
10
11
12
public static Double test3() {
Double b = null;
Double temp = null;
Double result = null;

if (b == null) {
result = temp;
} else {
result = b.doubleValue();
}
return result;
}

这段代码从语义上与三段式的那段代码是等价的,看看编译后的结果:

1
2
3
4
5
6
7
8
9
10
11
12
public static Double test3() {
Object b = null;
Object temp = null;
Double result = null;
if(b == null) {
result = (Double)temp;
} else {
result = Double.valueOf(((Double)b).doubleValue());
}

return result;
}

两个条件分支互相不影响,所以,对于 temp,由于不关心 double 值,所以,直接进行对象级别的赋值就好了,所以不会报空指针异常。

总结

在三段式中,如果一个可选项为 double 类型(无论变量还是常量),另一个可选项为值为 null 的 Double 类型变量或函数,就会因为拆包的问题报空指针异常。其它包装类型也是如此。平时在使用包装类,应当特别注意这一点。

谈谈 IT的文章均为原创或翻译(翻译会注明外文来源),转载请以链接形式标明本文地址: http://tantanit.com/java-san-duan-shi-zhong-bao-zhuang-lei-bao-kong-zhi-zhen-yi-chang/

谈谈IT

欢迎关注官方微信公众号获取最新原创文章