专注Java教育14年 全国咨询/投诉热线:400-8080-105
动力节点LOGO图
始于2009,口口相传的Java黄埔军校
首页 学习攻略 Java学习 Javase全套视频:三目运算符

Javase全套视频:三目运算符

更新时间:2020-02-28 10:28:42 来源:动力节点 浏览1520次


  三目运算符是我们经常在代码中使用的,a=(b==null?0:1);这样一行代码可以代替一个if-else,可以使代码变得清爽易读。但是,三目运算符也是有一定的语言规范的。在运用不恰当的时候会导致意想不到的问题。


Javase全套视频:三目运算符


  一、三目运算符


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


  二、自动装箱与自动拆箱


  基本数据类型的自动装箱(autoboxing)、拆箱(unboxing)是自J2SE5.0开始提供的功能。


  一般我们要创建一个类的对象实例的时候,我们会这样:Classa=newClass(parameters);当我们创建一个Integer对象时,却可以这样:Integeri=100;(注意:和inti=100;是有区别的)


  实际上,执行上面那句代码的时候,系统为我们执行了:Integeri=Integer.valueOf(100);这里暂且不讨论这个原理是怎么实现的(何时拆箱、何时装箱),也略过普通数据类型和对象类型的区别。


  我们可以理解为,当我们自己写的代码符合装(拆)箱规范的时候,编译器就会自动帮我们拆(装)箱。那么,这种不被程序员控制的自动拆(装)箱会不会存在什么问题呢?


  三、问题回顾


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


  publicstaticvoidmain(String[]args){


  Map<String,Boolean>map=newHashMap<>();


  Booleanb=map!=null?map.get("test"):false;


  System.out.println(b);


  }


  以上这段代码,是我们在不注意的情况下有可能经常会写的一类代码(在很多时候我们都爱使用三目运算符)。


  一般情况下,我们会认为以上代码Booleanb的最终得到的值应该是null。因为map.get("test")的值是null,而b又是一个对象,所以得到结果会是null。


  但是,以上代码会抛出NPE:


  Exceptioninthread"main"java.lang.NullPointerException


  首先可以明确的是,既然报了空指针,那么一定是有些地方调用了一个null的对象的某些方法。在这短短的两行代码中,看上去只有一处方法调用map.get("test"),但是我们也都是知道,map已经事先初始化过了,不会是Null,那么到底是哪里有空指针呢。


  我们接下来反编译一下该代码。看看我们写的代码在经过编译器处理之后变成了什么样。反编译后代码如下:


  publicstaticvoidmain(Stringargs[]){


  Mapmap=newHashMap();


  Booleanb=Boolean.valueOf(map==null?false:((Boolean)map.get("test")).booleanValue());


  System.out.println(b);


  }


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


  hashmap.get("test")->null;


  (Boolean)null->null;


  null.booleanValue()->报错


  好,问题终于定位到了。很明显,上面源代码中的map.get("test")在被编译成了


  (Boolean)map.get("test").booleanValue(),这是一种自动拆箱的操作。


  那么,为什么这里会发生自动拆箱呢?这个问题又如何解决呢?


  四、原理分析


  通过查看反编译之后的代码,我们准确的定位到了问题,分析之后我们可以得出这样的结论:NPE的原因应该是三目运算符和自动拆箱导致了空指针异常。


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


  Ifthesecondandthirdoperandshavethesametype(whichmaybethenulltype),thenthatisthetypeoftheconditionalexpression.


  IfoneofthesecondandthirdoperandsisofprimitivetypeT,andthetypeoftheotheristheresultofapplyingboxingconversion(§5.1.7)toT,thenthetypeoftheconditionalexpressionisT.


  Ifoneofthesecondandthirdoperandsisofthenulltypeandthetypeoftheotherisareferencetype,thenthetypeoftheconditionalexpressionisthatreferencetype.


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


  所以,结果就是:由于使用了三目运算符,并且第二、第三位操作数分别是基本类型和对象。所以对对象进行拆箱操作,由于该对象为null,所以在拆箱过程中调用null.booleanValue()的时候就报了NPE。


  五、问题解决


  如果代码这么写,就不会报错:


  Map<String,Boolean>map=newHashMap<String,Boolean>();


  Booleanb=(map!=null?map.get("test"):Boolean.FALSE);


  就是保证了三目运算符的第二第三位操作数都为对象类型。这样就不会发生自动拆箱操作,以上代码得到的b的结果为null。


Javase全套视频:三目运算符


      以上就是动力节点Java培训机构小编介绍的“Javase全套视频:三目运算符”的内容,希望对大家有帮助,如有疑问,请在线咨询,有专业老师随时为你服务。


提交申请后,顾问老师会电话与您沟通安排学习

免费课程推荐 >>
技术文档推荐 >>