自动拆箱致使空指针异常

1、三目运算符java

对于条件表达式b?x:y,先计算条件b,而后进行判断。若是b的值为true,计算x的值,运算结果为x的值;不然,计算y的值,运算结果为y的值。一个条件表达式从不会既计算x,又计算y。条件运算符是右结合的,也就是说,从右向左分组计算。例如,a?b:c?d:e将按a?b:(c?d:e)执行。程序员

2、自动装箱与自动拆箱express

基本数据类型的自动装箱(autoboxing)、拆箱(unboxing)是自J2SE 5.0开始提供的功能。 通常咱们要建立一个类的对象实例的时候,咱们会这样: Class a = new Class(parameters); 当咱们建立一个Integer对象时,却能够这样: Integer i = 100;(注意:和 int i = 100;是有区别的 ) 实际上,执行上面那句代码的时候,系统为咱们执行了: Integer i = Integer.valueOf(100); 这里暂且不讨论这个原理是怎么实现的(什么时候拆箱、什么时候装箱),也略过普通数据类型和对象类型的区别。咱们能够理解为,当咱们本身写的代码符合装(拆)箱规范的时候,编译器就会自动帮咱们拆(装)箱。那么,这种不被程序员控制的自动拆(装)箱会不会存在什么问题呢?app

3、问题回顾指针

首先,经过你已有的经验看一下下面这段代码。若是你获得的结果和后文分析的结果一致(而且你知道原理),那么请忽略本文。若是不一致,请跟我探索下去。code

Map<String,Boolean> map =  new HashMap<String, Boolean>();
Boolean b = (map!=null ? map.get("test") : false);

以上这段代码,是咱们在不注意的状况下有可能常常会写的一类代码(在不少时候咱们都爱使用三目运算符)。固然,这段代码是存在问题的,执行该代码,会报NPE.对象

Exception in thread "main" java.lang.NullPointerException

首先能够明确的是,既然报了空指针,那么必定是有些地方调用了一个null的对象的某些方法。在这短短的两行代码中,看上去只有一处方法调用map.get("test"),可是咱们也都是知道,map已经事先初始化过了,不会是Null,那么究竟是哪里有空指针呢。咱们接下来反编译一下该代码。看看咱们写的代码在通过编译器处理以后变成了什么样。get

反编译后代码以下:编译器

HashMap hashmap = new HashMap();
Boolean boolean1 = Boolean.valueOf(hashmap == null ? false : ((Boolean)hashmap.get("test")).booleanValue());

看完这段反编译以后的代码以后,通过分析咱们大概能够知道问题出在哪里。((Boolean)hashmap.get("test")).booleanValue()的执行过程及结果以下:hash

hashmap.get(“test”)->null;

(Boolean)null->null;

null.booleanValue()->报错

好,问题终于定位到了。那么接下来看看如何解决该问题以及为何会出现这种问题。

4、原理分析

经过查看反编译以后的代码,咱们准确的定位到了问题,分析以后咱们能够得出这样的结论:NPE的缘由应该是三目运算符和自动拆箱致使了空指针异常。

那么,这段代码为何会自动拆箱呢?这实际上是三目运算符的语法规范。参见jls-15.25,摘要以下:

If the second and third operands have the same type (which may be the null type), then that is the type of the conditional expression.

If one of the second and third operands is of primitive type T, and the type of the other is the result of applying boxing conversion (§5.1.7) to T, then the type of the conditional expression is T.

If one of the second and third operands is of the null type and the type of the other is a reference type, then the type of the conditional expression is that reference type.

简单的来讲就是:当第二,第三位操做数分别为基本类型和对象时,其中的对象就会拆箱为基本类型进行操做。

因此,结果就是:因为使用了三目运算符,而且第2、第三位操做数分别是基本类型和对象。因此对对象进行拆箱操做,因为该对象为null,因此在拆箱过程当中调用null.booleanValue()的时候就报了NPE。

5、问题解决

若是代码这么写,就不会报错:

Map<String,Boolean> map =  new HashMap<String, Boolean>();
Boolean b = (map!=null ? map.get("test") : Boolean.FALSE);

就是保证了三目运算符的第二第三位操做数都为对象类型。

这和三目运算符有关。

相关文章
相关标签/搜索