背景
在使用三目运算符的时候系统报了空指针,
我是给已个Integer类型的属性赋值
Integer a=10;
a=a==9?0:null
单看代码一致看不出哪里出错了,经反编译null.intValue
经查询如下解释
写在前面:
三目运算符是我们经常在代码中使用的,
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)
; 这里暂且不讨论这个原理是怎么实现的(何时拆箱、何时装箱),也略过普通数据类型和对象类型的区别。我们可以理解为,当我们自己写的代码符合装(拆)箱规范的时候,编译器就会自动帮我们拆(装)箱。那么,这种不被程序员控制的自动拆(装)箱会不会存在什么问题呢?
三、问题回顾
首先,通过你已有的经验看一下下面这段代码。如果你得到的结果和后文分析的结果一致(并且你知道原理),那么请忽略本文。如果不一致,请跟我探索下去。
以上这段代码,是我们在不注意的情况下有可能经常会写的一类代码(在很多时候我们都爱使用三目运算符)。当然,这段代码是存在问题的,执行该代码,会报NPE.
首先可以明确的是,既然报了空指针,那么一定是有些地方调用了一个null的对象的某些方法。在这短短的两行代码中,看上去只有一处方法调用map.get("test")
,但是我们也都是知道,map已经事先初始化过了,不会是Null,那么到底是哪里有空指针呢。我们接下来反编译一下该代码。看看我们写的代码在经过编译器处理之后变成了什么样。
反编译后代码如下:
看完这段反编译之后的代码之后,经过分析我们大概可以知道问题出在哪里。((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。
五、问题解决
如果代码这么写,就不会报错:
就是保证了三目运算符的第二第三位操作数都为对象类型。
这和三目运算符有关。
相关推荐
在编程世界中,三目运算符和正则表达式是两个非常重要的概念,它们各自扮演着独特的角色,同时也常被结合起来使用,以提高代码的简洁性和效率。让我们深入探讨这两个主题。 首先,三目运算符,也称为条件运算符,是...
三目运算符习题及参考答案
### Java 三目运算符详解 #### 一、基本概念 在Java编程语言中,三目运算符(也称为条件运算符)是一种简洁且高效的方式来根据条件选择两个可能的值中的一个。它由三个操作数组成,因此得名“三目”运算符。 ####...
本文探讨了如何利用短路法和逗号表达式来替代传统的if和三目运算符,实现条件分支功能,这不仅是一种编程技巧,也有助于深入理解语言特性和逻辑运算的短路行为。 首先,我们回顾一下if-else语句的基本结构和三目...
三目运算符的实例 。
c++三目运算符?: 语句的使用,介绍了对分数分级方式使用时的简便之处,可以节约代码书写量
在C语言中,三目运算符(也称为条件运算符)是一种简洁的语法结构,用于根据条件执行不同的表达式。这个运算符具有三个操作数,因此得名“三目”。在C语言中,它的语法形式如下: `条件 ? 表达式1 : 表达式2` 如果...
在编程领域,三目运算符是一种简洁而高效的条件判断表达方式,主要应用于C、C++、Java、Python等编程语言中。它以一种紧凑的形式替代了传统的if-else语句,使得代码更加简洁易读。本资源提供的"三目运算符"练习示例...
### Java入门教程:数据类型与三目运算符详解 #### 数据类型概述 Java是一种静态类型的编程语言,这意味着在编译时必须明确指定每个变量的数据类型。Java提供了多种内置的数据类型来满足不同的需求,包括整型(如`...
### Python中的三目运算符详解 #### 一、引言 在编程过程中,经常会遇到根据某个条件选择执行不同代码逻辑的需求。Python作为一种简洁高效的编程语言,提供了多种方式来实现这样的功能,其中之一就是所谓的“三目...
三目运算符,也称为条件运算符,是编程语言中的一种高效表达方式,它允许根据条件的真假来决定执行不同的代码路径。这个运算符在C、C++、Java等语言中广泛存在,而在Python中则有其独特的实现方式。下面我们将深入...
判断语句 三目运算符代码
在iOS开发中,三目运算符(三元运算符)是一种高效、简洁的代码编写方式,尤其在处理条件判断和赋值时。它的符号是 `? :`,用于替代传统的 `if-else` 语句。这篇教程将深入探讨这个运算符在iOS中的应用和一些特殊的...
Java利用三目运算符比较三个数字的大小 在 Java 编程语言中,三目运算符是一种非常有用的操作符,能够帮助我们简洁地实现一些逻辑判断和计算。本文将详细介绍如何使用 Java 三目运算符比较三个数字的大小,并计算出...
三目运算符.cpp
Java中的三目运算符,也称为条件运算符,是编程语言中的一种简洁的表达方式,用于根据条件返回一个值。这个运算符在Java中经常被用到,特别是在简化代码和提高可读性方面。本练习旨在帮助你深入理解和熟练运用Java的...
三目运算符.py
在Java编程语言中,三目运算符(Ternary Operator)和运算符的优先级是初学者常常会遇到的重要概念。这两个知识点对于编写简洁、高效的代码至关重要。让我们深入了解一下它们。 首先,三目运算符是一种简洁的条件...
0400_极智开发_解读python 三目运算符