写在前面:

三目运算符是我们经常在代码中使用的,a= (b==null?0:1); 这样一行代码可以代替一个 if-else,可以使代码变得清爽易读。但是,三目运算符也是有一定的语言规范的。在运用不恰当的时候会导致意想不到的问题。前段时间遇到(一个由于使用三目运算符导致的问题,其实是因为有三目运算符和自动拆箱同时使用(虽然自动拆箱不是我主动用的)。

一、三目运算符

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

二、自动装箱与自动拆箱

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

三、问题回顾

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

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,那么到底是哪里有空指针呢。我们接下来反编译一下该代码。看看我们写的代码在经过编译器处理之后变成了什么样。

反编译后代码如下:

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

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

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

(Boolean)null->null;

null.booleanValue()->报错

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

四、原理分析

通过查看反编译之后的代码,我们准确的定位到了问题,分析之后我们可以得出这样的结论: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.

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

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

五、问题解决

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

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

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

这和三目运算符有关。

你真的会用三目运算符吗?相关推荐

  1. swift3 0 流控制

    `1. if else if 判断条件 { ///条件成立 }else{ ///条件不成立 } 注意:判断条件必须为 true 或者false 不能是1,2 或者存在的对象,不然系会编译错误,这点和O ...

  2. 你真的了解Java中的三目运算符吗

    转载自 你真的了解Java中的三目运算符吗 三目运算符是我们经常在代码中使用的,a= (b==null?0:1);这样一行代码可以代替一个if-else,可以使代码变得清爽易读. 但是,三目运算符也是 ...

  3. [转载] 你真的会用 Java 中的三目运算符吗

    参考链接: Java中的按位运算符 转载:http://blog.jobbole.com/93511/ 写在前面: 三目运算符是我们经常在代码中使用的,a= (b==null?0:1); 这样一行代码 ...

  4. 细思极恐,你真的会写 Java 吗

    点击上方 好好学java ,选择 星标 公众号 重磅资讯.干货,第一时间送达 今日推荐:牛人 20000 字的 Spring Cloud 总结,太硬核了~ 非常非常不错的一篇文章,文中提到的很多实践都 ...

  5. java三目运算符判断boonlean,java三元运算符

    首先看一下三元运算符的格式 [条件语句] ? [表达式1] : [表达式2] 其中如条件语句为真执行表达式1,否则执行表达式2.简单的例子就不举了,来点其它的.在JDK1.5以前的版本中,表达式1和表 ...

  6. Java中的三目运算符可能出现的问题

    你真的了解Java中的三目运算符吗? 原创 2018-04-27 刨根问底的 Hollis Hollis Hollis 微信号 hollischuang 功能介绍 一个对Coding有着独特追求的人. ...

  7. Python学习 Day8-2 python的三元表达式(三目运算符)、lambda表达式、内置函数

    Python中的三元表达式(三目运算符) 语法:为真时的结果 if 判断条件 else 为假时的结果(注意,没有冒号) >>print(1 if 5 > 3 else 0) 1 Py ...

  8. Java基础语法知识你真的都会吗?

    第一阶段 JAVA基础知识 第二章 Java基础语法知识 在我们开始讲解程序之前,命名规范是我们不得不提的一个话题,虽说命名本应该是自由的,但是仍然有一定的"潜规则",通过你对命名 ...

  9. 细思极恐-你真的会写java吗?

    细思极恐-你真的会写java吗? 导语 自2013年毕业后,今年已经是我工作的第4个年头了,总在做java相关的工作,终于有时间坐下来,写一篇关于java写法的一篇文章,来探讨一下如果你真的是一个ja ...

最新文章

  1. raid5数据恢复方法,服务器磁盘阵列数据恢复成功案例
  2. IOS学习笔记(四)之UITextField和UITextView控件学习
  3. shell按长度排序
  4. java 反编译 手游_Java反编译器(DJ Java Decompiler)
  5. python-装饰器实现pv-uv
  6. 深度学习简介(一)——卷积神经网络
  7. 解决GitHub下载速度慢下载失败的问题
  8. 论一只爬虫的自我修养(第二天)
  9. sql server内置存储过程、查看系统信息
  10. Oracle 单实例 迁移到 RAC 实例 -- 使用导出导入方法
  11. 菜鸟从零学习数据库(三)——存储过程
  12. VB6 用ODBC连接数据库
  13. postman接口测试七
  14. unity怎么制作云飘动_现实的动态云系统特效脚本Unity3D素材资源
  15. 概率论的学习和整理10:古典概型 和 二项分布(N重伯努利试验)
  16. MySQL数据库基础表格——增删改查(下)
  17. BT网站关了,正版电影数字发行在线收费下载 的机会?
  18. k8s存储之Volumes卷类型
  19. amap 高德 地图打点 地图描点 描点居中 清除打点
  20. 毕业设计 - 基于java web的在线考试系统【源码+论文】

热门文章

  1. python在线 培训
  2. folly库安装(1)cmake和gcc的安装、升级
  3. 大数据·实战个例“宏”分析
  4. STM32学习之ILI9341控制显示屏输出(一)
  5. POI Word表格删除行removeRow()
  6. MessageFormatter
  7. jquery服务器文件保存到本地,jQuery本地存储
  8. Mysql在表中添加约束条件
  9. 江苏省高等学校计算机等级考试成绩查询,江苏计算机等级考试成绩查询入口
  10. 电路(第三章、线性直流电路一般分析方法)