记一次java中三元表达式的坑(避免踩坑)

简介: 这个问题是三元表达式会在计算的时候出现拆箱的运算,造成空指针异常

一、问题重现


v2-3d3d052b331b079fe58cd6e47132799a_1440w.jpg

代码很简单,a是包装类型Integer,初始值是null,b通过三元表达式进行赋值。运行一下这个代码就会出现空指针异常:

v2-a120e3d4d6182d475e1dd3933f712d4f_1440w.jpg为什么会出现这个现象呢?下面我们来分析一下:


二、问题分析


刚刚这个空指针现象很容易我们就想到类型转化上,三元表达式的类型转换同样要遵守一定的规则才可以。


1、三元操作符类型的转换规则:


(1)若两个操作数不可转换,则不做转换,返回值为Object类型

比如Object b = flag ? A : B,此时A和B是两个不同的对象,不可转换,那就把最终结果赋值给Object


(2)若两个操作数是明确类型的表达式(比如变量),则按照正常的二进制数字来转换,int类型转换为long类型,long类型转换为float类型等。


这个就比较容易理解了,比如float b = flag ? 1:1.0f。1为int类型向上转即可。


(3)若两个操作数中有一个是数字S,另外一个是表达式,且其类型标示为T,那么,若数字S在T的范围内,则转换为T类型;若S超出了T类型的范围,则T转换为S类型。


这种情况就是刚刚我们所演示的例子,Integer b = flag ? 1 *2: a,结果是b=a,但是a是null,要强制转换成Integer(1 * 2的类型),于是就出现了空指针。


(4)若两个操作数都是直接量数字,则返回值类型为范围较大者。

这种情况和第二种类似。


现在答案基本上出来了,出现空指针的原因是,a=null,要强制转换Integer,于是出现了空指针,因为虚拟机看到一个null就找不到要转化的对象了。


2、反编译分析


现在我们找到Test的字节码文件,输入javap -c命令,反编译一下:

v2-228d1428d4a4e7544d90e1081f582bba_1440w.jpg

答案现在应该清楚了,


3、为什么要拆箱(重点)


为什么要对a进行拆箱,直接把a=null赋值给b不就完事了嘛。这一点就需要我们注意一下那个前提条件,也就是说一个是数字,一个是表达式,刚刚的那个例子也验证了这个观点,现在我不是表达式,再来验证一下:


v2-1f870eb7c4ebe3b6033eaac2db864cba_1440w.jpg

现在我们可以看到不是表达式,依然会出现这个错误。别着急,还有让你更晕的,我们再来改变一下代码:

v2-4a31b40ccf7a9f7ae55ec18b935d8095_1440w.jpg

我测试了很多不同的案例,基本上就分为这两种情况。原因如下:


条件表达式?表达式 1 :表达式 2,假设结果是表达式2


(1)表达式1和2都为null,表达式2看到1是null,则不会进行拆箱。


(2)表达式1为数字或者是表达式,表达式2根据1的类型进行拆箱。


也就是说表达式2主要依据表达式1判断是否进行拆箱操作。


三、问题解决


解决方案很简单,那就是只要遇见null在三元表达式里,就尽量转化为if结构。

相关文章
|
1天前
|
Java 开发者
Java一分钟之-Lambda表达式与函数式接口
【5月更文挑战第12天】Java 8引入的Lambda表达式简化了函数式编程,与函数式接口结合,实现了代码高效编写。本文介绍了Lambda的基本语法,如参数列表、箭头符号和函数体,并展示了如何使用Lambda实现`Runnable`接口。函数式接口仅有一个抽象方法,可与Lambda搭配使用。`@FunctionalInterface`注解用于确保接口具有单一抽象方法。文章还讨论了常见的问题和易错点,如非函数式接口、类型冲突以及Lambda表达式的局部变量可见性,并提供了避免这些问题的策略。通过理解Lambda和函数式接口,开发者能提高代码可读性和效率。
40 4
|
1天前
|
Java
探索Java世界的奇妙工具——运算符与表达式运算符
探索Java世界的奇妙工具——运算符与表达式运算符
7 0
|
1天前
|
Java API
Java 8新特性之Lambda表达式与Stream API实践指南
【5月更文挑战第15天】 随着Java语言的不断发展,Java 8作为一个重要的版本,引入了许多令人兴奋的新特性。其中,Lambda表达式和Stream API是Java 8最受关注的两个特性。本文将深入探讨Lambda表达式的基本概念、语法和使用场景,以及如何结合Stream API实现更加简洁、高效的代码编写。通过实例演示,帮助读者快速掌握这两个新特性,提高Java编程能力。
|
1天前
|
Java
Java正则表达式去掉非汉字字符
【5月更文挑战第11天】Java正则表达式去掉非汉字字符
15 3
|
1天前
|
Java API 开发者
Java中Lambda表达式的深入理解与应用
【5月更文挑战第12天】在Java 8之后,Lambda表达式已经成为了Java开发者必备的技能之一。Lambda表达式以其简洁、灵活的特点,大大提高了编程的效率。本文将深入探讨Lambda表达式的基本概念,语法规则,以及在实际开发中的应用,帮助读者更好地理解和使用Lambda表达式。
|
1天前
|
Java 程序员 API
Java 8新特性之Lambda表达式与Stream API的深度解析
【5月更文挑战第12天】本文将深入探讨Java 8中的两个重要新特性:Lambda表达式和Stream API。我们将从基本概念入手,逐步深入到实际应用场景,帮助读者更好地理解和掌握这两个新特性,提高Java编程效率。
41 2
|
1天前
|
算法 安全 Java
Java表达式和规则引擎的比较与考量
Java表达式和规则引擎的比较与考量
10 0
|
1天前
|
Java
【JAVA进阶篇教学】第二篇:JDK8中Lambda表达式
【JAVA进阶篇教学】第二篇:JDK8中Lambda表达式
|
1天前
|
Java
Java一分钟之运算符与表达式初探
【5月更文挑战第7天】本文介绍了Java中的主要运算符,包括算术、比较、逻辑、位、赋值和条件运算符。讨论了类型转换、运算顺序和逻辑短路等常见问题,并提供了避免错误的建议。通过代码示例展示了运算符的使用,强调理解运算符对于编写高效Java代码的重要性。
22 0
Java一分钟之运算符与表达式初探
|
1天前
|
安全 Java 程序员
Java 8新特性之Lambda表达式
【5月更文挑战第5天】 本文将介绍Java 8中的一个重要新特性——Lambda表达式。Lambda表达式是Java 8引入的一种简洁、易读的函数式编程语法,它允许我们将函数作为参数传递给方法,或者作为返回值。通过使用Lambda表达式,我们可以编写更简洁、更易读的代码,提高开发效率。