今天在项目中改领导要求的代码表现的时候发现了一个很有趣的问题。

但是的代码情况类似如下:

1
2
Integer test1 = null;
System.out.println("test1 = " + (test1+1));

看到代码后,这样在test1为null的情况下,那么打印语句肯定会抛空指针异常的,随即我修改了代码,代码像下面看到的这样:

1
2
Integer test1=null;
System.out.println("test1 = " + (test1==null?test1:(test1+1)));
1
 

就是上面的代码出现了同样的问题,还是在抛空指针一场的问题,不应该啊?!难道是java对三元式的处理是全部计算的?(猜想1)于是我写了下面的代码进行验证:

代码1:

1
System.out.println("test1 = "null);

代码2:

1
2
Integer test1=null;
System.out.println("test1 = " + (test1==null?-1:(test1+1)));

代码1只是为了验证可以打印null这种情况的。

代码2为了验证猜想1,但是呢,代码2是正常被执行了的,猜想1猜想失败了,既然貌似是三元式的第二个元的引起,于是我又猜想错误第三个元没有关系(猜想2),我用下面的代码进行验证:

代码3:

1
2
Integer test1=null;
System.out.println("test1 = "+ (test1==null?test1:test1));

代码3如上所说是为了排除和第三个元无关的,然后猜测代码正常执行的,但是,实际情况还是报空指针异常了。

猜测1和猜测2失败后,就能得到,跟三元式的2和3元都有关系。

我有想起来三元式的形式是:  expression1?expression2:expression3

于是有了下面的代码:

代码4:

1
2
3
Integer test1=null;
Integer test2=(test1==null?test1:(test1=123));
System.out.println("test1 = " + test1);

代码4正常执行,输出了test1 = null ,又看着第三个元没有执行。

再验证:

代码5:

1
2
3
Integer test1=null;
Integer test2=(test1==null?test1:(System.out.println("test1")));
System.out.println("test1 = " + test1);

代码5语法直接都有问题,不应该啊?!  这段代码是应该出问题的,自己理解有误,在2,3元上需要一个返回值的计算式而System.out.println("test1")没有返回值,所以理应出错。

结论:

1.java中,三元式中的第二和第三个元都进行了检查,检查的方法需要查看java中对三元式的实现才能确定。

2.expression1?expression2:expression3 这样的形式的三元式,看看就行了,具体需要在使用的时候进行代码验证,否则就像本次问题一样,知识不足造成了bug的出现。

以后还是尽量少用三元式,以防止预想之外的结果。

上面问题的解决代码:

1
2
3
4
5
6
Integer tmp= null;
if(test1==null){
    tmp=null;
}else{
    tmp=test1;
}

(完)

今天在stackoverflow中提出了这个问题,然后有大牛解决了

http://stackoverflow.com/questions/18124745/java-ternary-operator-and-nullpointerexception

在java中关于三元运算符有这么一个特性:

1.在第二个元和第三个元的类型相同的时候,那么返回一个2,3元的类型。

(test1==null?test1:test1)也就是这句代码没有出错,返回的是一个Integer类型的值,Integer类型是允许有null的,所以本身代码就不会出问题。

2.在第二个元或者第三个元有基本类型的T的时候,那么不管另一个元是什么类型,都要最小化成基本类型T,所以如下的代码返回的是int类型,但是test1是null,这里有一个boxing的处理,所以造成了,返回的int类型有null值,最终造成了NPE异常的出现:

1
2
test2=(test1==null?test1:-1);
test2=(test1==null?test1:(test1+1));

问题解决,从本个问题看来,是我的知识不足造成的,下面是java给的官方解释:

http://docs.oracle.com/javase/specs/jls/se7/html/jls-15.html#jls-15.25

(完)

本文出自 “越努力,越幸运” 博客,请务必保留此出处http://actor.blog.51cto.com/1764681/1265514

代码:

  1. Map<String, Integer> map = new HashMap<String, Integer>();
  2. map.put("count", null);
  3. Integer it = map == null ? 0 : map.get("count");

注意:在第三行,会抛出java.lang.NullPointerException信息。因为分析:表达式二的类型为int,整个表达式类型为Integer,JDK5.0会自动打包,所以表达式三 会获得一个Integer,然后转成int,再转成Integer,如果是NULL在转成int的时候抛出空指针异常。

附一篇博客:ava 条件表达式(即三元操作符)的陷阱

地址:http://apps.hi.baidu.com/share/detail/5319426

下面的程序将会打印出什么呢?

  1. public class DosEquis{
  2. public static void main(String[] args){
  3. char x = 'X';
  4. int i = 0;
  5. System.out.println(true ? x : 0);
  6. System.out.println(false ? i : x);
  7. }
  8. }

这个程序由两个变量声明和两个print语句构成。第一个print语句计算条件表达式(true ? x : 0)并打印出结果,这个结果是char类型变量x的值’X’。而第二个print语句计算表达式(false ? i : x)并打印出结果,这个结果还是依旧是’X’的x,因此这个程序应该打印XX。

然而,如果你运行该程序,你就会发现它打印出来的是X88。这种行为看起来挺怪的。第一个print语句打印的是X,而第二个打印的却是88。它们的不同行为说明了什么呢?

答案就在规范有关条件表达式部分的一个阴暗的角落里。请注意在这两个表达式中,每一个表达式的第二个和第三个操作数的类型都不相同:x是char类型的,而0和i都是int类型的。混合类型的计算会引起混乱,而这一点比在条件表达式中比在其它任何地方都表现得更明显。你可能考虑过,这个程序中两个条件表达式的结果类型是相同的,就像它们的操作数类型是相同的一样,尽管操作数的顺序颠倒了一下,但是实际情况并非如此。

确定条件表达式结果类型的规则过于冗长和复杂,很难完全记住它们,但是其核心就是一下三点: 
如果第二个和第三个操作数具有相同的类型,那么它就是条件表达式的类型。换句话说,你可以通过绕过混合类型的计算来避免大麻烦。 
    如果一个操作数的类型是T,T表示byte、short或char,而另一个操作数是一个int类型的常量表达式,它的值是可以用类型T表示的,那么条件表达式的类型就是T。 
否则,将对操作数类型运用二进制数字提升,而条件表达式的类型就是第二个和第三个操作数被提升之后的类型。

2、3两点是关键。在程序的两个条件表达式中,一个操作数的类型是char,另一个的类型是int。在两个表达式中,int操作数都是0,它可以被表示成一个char。然而,只有第一个表达式中的int操作数是常量(0),而第二个表达式中的int操作数是变量(i)。因此,第2点被应用到了第一个表达式上,它返回的类型是char,而第3点被应用到了第二个表达式上,其返回的类型是对int和char运用了二进制数字提升之后的类型,即int。

条件表达式的类型将确定哪一个重载的print方法将被调用。对第一个表达式来说,print(char)将被调用,而对第二个表达式来说,PrintStream.print(int)将被调用。前一个重载方法将变量x的值作为Unicode字符(X)来打印,而后一个重载方法将其作为一个十进制整数(88)来打印。

总之,通常最好是在条件表达式中使用类型相同的第二和第三操作数。否则,你和你的程序的读者必须要彻底理解这些表达式行为的复杂规范。

对 语言设计者来说,也许可以设计一个牺牲掉了部分灵活性,但是增加了简洁性的条件操作符。例如,要求第二和第三操作数必须就有相同的类型,这看起来就很合 理。或者,条件操作符可以被定义为对常量没有任何特殊处理。为了让这些选择对程序员来说更加容易接受,可以提供用来表示所有原始类型字面常量的语法。这也 许确实是一个好注意,因为它增加了语言的一致性和完备性,同时又减少了对转型需求。

转自:http://grzrt.iteye.com/blog/1606863

java语言中使用三元式的时候应该注意的问题的更多相关文章

  1. Java语言中的面向对象特性总结

    Java语言中的面向对象特性 (总结得不错) [课前思考]  1. 什么是对象?什么是类?什么是包?什么是接口?什么是内部类?  2. 面向对象编程的特性有哪三个?它们各自又有哪些特性?  3. 你知 ...

  2. Java语言中的面向对象特性:封装、继承、多态,面向对象的基本思想(总结得不错)

    Java语言中的面向对象特性(总结得不错) [课前思考] 1. 什么是对象?什么是类?什么是包?什么是接口?什么是内部类? 2. 面向对象编程的特性有哪三个?它们各自又有哪些特性? 3. 你知道jav ...

  3. Java语言中的正则表达式

    正则表达式是什么? 正则表达式是一种强大而灵活的文本处理工具.初学正则表达式时,其语法是一个难点,但它确实是一种简洁.动态的语言.正则表达式提供了一种完全通用的方式,能够解决各种字符串处理相关的问题: ...

  4. JAVA语言中的修饰符

    JAVA语言中的修饰符 -----------------------------------------------01--------------------------------------- ...

  5. JAVA语言中冒号的用法

    近来由于本人要介入android平台的开发,所以就买了本JAVA语言的书学习.学习一段时间来,我的感觉是谭浩强就是厉害,编写的<C编程语言>系列丛书不愧是经典.书中对C语言的介绍既系统又全 ...

  6. Java语言中的异常处理

    Java语言中的异常处理包括声明异常.抛出异常.捕获异常和处理异常四个环节.   throw用于抛出异常.   throws关键字可以在方法上声明该方法要抛出的异常,然后在方法内部通过throw抛出异 ...

  7. 列举java语言中反射的常用方法

    package review;/*12:43 2019/7/21*/ import model.AnotherClass; import model.OneClassMore; import mode ...

  8. Java语言中使用OpenMP

    从去年年中,开始学习Java,主要是维护公司用Java编写的服务器软件.目前,该服务器软件遇到一个问题,在下载大文件时,如果同时下载的用户很多, 服务器软件工作会出现异常,有的用户无法下载.服务器硬件 ...

  9. Java语言中的这些知识点有没有用过,工作中有没有入过这些坑?

    在Java语言中,有一些相对生僻的知识,平时用的机会可能不是很多,但如果不了解不掌握这些知识点的话,也可能会掉入陷阱之中,今天我们就来初步梳理一下: 1. goto是java语言中的关键字. &quo ...

随机推荐

  1. Leetcode题目215.数组中的第K个最大元素(中等)

    题目描述: 在未排序的数组中找到第 k 个最大的元素.请注意,你需要找的是数组排序后的第 k 个最大的元素,而不是第 k 个不同的元素. 示例 1: 输入: [3,2,1,5,6,4] 和 k = 2 ...

  2. 微信小程序之scroll-view的坑

    好久没动小程序了,今天打算复习复习,结果刚写了一个scroll-view就遇到了一个坑,这怎么能忍,对比看文档也没发现那里出了问题,没办法只能去翻翻微信给的demo,发现scroll-view一个必要 ...

  3. linux基础技巧

    命令行颜色显示: \[\e]0;\u@\h: \w\a\]${debian_chroot:+($debian_chroot)}\[\033[01;32m\]\u@\h\[\033[00m\]:\[\0 ...

  4. python 操作excel openpyxl

    1 安装 pip install openpyxl 如果装不上,请指定安装源来安装 pip install -i https://pypi.douban.com/simple openpyxl 如果e ...

  5. P1115 最大子段和&P1719 最大加权矩形

    上接:DP&图论 DAY 1 上午 这两个题本质是一个亚子,所以放一起啦 DPDPDPDPDPDPDPDP P1115 最大子段和 题解 因为题目要求的是一段连续的区间,所以前缀和搞暴力??? ...

  6. Handler处理消息

    UI主线程通过Looper循环查询消息队列UI_MQ,当发现有消息存在时会将消息从消息队列中取出.首先分析消息,通过消息的参数判断该消息对应的Handler,然后将消息分发到指定的Handler进行处 ...

  7. 008-centos6.5搭建web服务【nginx-tomcat8-jre8】

    一.机器配置 yum install vim 1.1.Linux最大进程以及打开文件数 ulimit -n和-u可以查看linux的最大进程数和最大文件打开数. ulimit -a 展示所有 临时方法 ...

  8. 使用Mock 测试 controller层

    package action; import org.junit.Before;import org.junit.Test;import org.junit.runner.RunWith;import ...

  9. Java日志体系(四)slf4j

    1.1 简介 与commons-logging相同,slf4j也是一个通用的日志接口,在程序中与其他日志框架结合使用,并对外提供服务. Simple Logging Facade for Java简称 ...

  10. EM算法:入门案例

    概率分布 4种实验结果 \(E_1\) \(E_2\) \(E_3\) \(E_4\) 记录它们发生的次数 \(y_1\) \(y_2\) \(y_3\) \(y_4\) 记录次数结果 125 18 ...