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

最近在开发中遇到一个莫名其妙的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类型变量或函数,就会因为拆包的问题报空指针异常。其它包装类型也是如此。平时在使用包装类,应当特别注意这一点。

© 2018 谈谈IT All Rights Reserved. 本站访客数人次 本站总访问量
Theme by hiero