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

参考链接: Java中的按位运算符

转载:http://blog.jobbole.com/93511/ 写在前面: 

 

 

 三目运算符是我们经常在代码中使用的,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); 这里暂且不讨论这个原理是怎么实现的(何时拆箱、何时装箱),也略过普通数据类型和对象类型的区别。我们可以理解为,当我们自己写的代码符合装(拆)箱规范的时候,编译器就会自动帮我们拆(装)箱。那么,这种不被程序员控制的自动拆(装)箱会不会存在什么问题呢? 

三、问题回顾 

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

 

  

   

   

   Java

   

  

 

  Map<String,Boolean> map =  new HashMap<String, Boolean>();

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

  

  

   

       

       

        1

        

       

        2

        

        

       

       

        Map

        <

        String

        ,

        Boolean

        >

         

        map

         

        =

          

        new

         

        HashMap

        <

        String

        ,

         

        Boolean

        >

        (

        )

        ;

        

        

        Boolean

         

        b

         

        =

         

        (

        map

        !=

        null

         

        ?

         

        map

        .

        get

        (

        "test"

        )

         

        :

         

        false

        )

        ;

        

        

  

 

以上这段代码,是我们在不注意的情况下有可能经常会写的一类代码(在很多时候我们都爱使用三目运算符)。当然,这段代码是存在问题的,执行该代码,会报NPE. 

 

  

  

  

 

  Exception in thread "main" java.lang.NullPointerException

  

  

   

       

       

        1

        

        

       

       

        Exception 

        in

         

        thread

         

        "main"

         

        java

        .

        lang

        .

        NullPointerException

        

        

  

 

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

反编译后代码如下: 

 

  

   

   

   Java

   

  

 

  HashMap hashmap = new HashMap();

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

  

  

   

       

       

        1

        

       

        2

        

        

       

       

        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。 

五、问题解决 

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

 

  

   

   

   Java

   

  

 

  Map&lt;String,Boolean&gt; map =  new HashMap&lt;String, Boolean&gt;();

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

  

  

   

       

       

        1

        

       

        2

        

        

       

       

        Map

        &

        lt

        ;

        String

        ,

        Boolean

        &

        gt

        ;

         

        map

         

        =

          

        new

         

        HashMap

        &

        lt

        ;

        String

        ,

         

        Boolean

        &

        gt

        ;

        (

        )

        ;

        

        

        Boolean

         

        b

         

        =

         

        (

        map

        !=

        null

         

        ?

         

        map

        .

        get

        (

        "test"

        )

         

        :

         

        Boolean

        .

        FALSE

        )

        ;

        

        

  

 

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

这和三目运算符有关。

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.mzph.cn/news/540254.shtml

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

HTTP Keep-Alive模式

1、什么是Keep-Alive模式&#xff1f; 我们知道HTTP协议采用“请求-应答”模式&#xff0c;当使用普通模式&#xff0c;即非KeepAlive模式时&#xff0c;每个请求/应答客户和服务器都要新建一个连接&#xff0c;完成 之后立即断开连接&#xff08;HTTP协议为无连接的协议&#…

[转载] java:比较运算符

参考链接&#xff1a; Java中的new运算符 1.compareTo()方法: compareTo()方法返回的是一个int类型值. //声明的值 BigDecimal t_sell1 new BigDecimal(); BigDecimal t_sell2 new BigDecimal(); if(t_sell1.compareTo(t_sell2)0){ return "t_sell1的值等于t_sell2&…

[转载] java左移右移和无符号右移

参考链接&#xff1a; Java中的按位右移运算符 ###知识点 java的三种位移运算符&#xff1a; <<&#xff1a;左移运算符&#xff0c;num << 1,相当于num乘以2 >>&#xff1a;右移运算符&#xff0c;num >> 1,相当于num除以2 >>>&#xff1a…

Script:List OBJECT DEPENDENT

以下脚本用以列出数据库中对象的依赖性:select D_OBJ#, 本文转自maclean_007 51CTO博客&#xff0c;原文链接: http://blog.51cto.com/maclean/1276767

[转载] java避免空指针异常_第1部分:在现代Java应用程序中避免空指针异常

参考链接&#xff1a; Java的instanceof及其应用 java避免空指针异常 空做与不做 (Null do’s and don’ts) In the talk Null References: The Billion Dollar Mistake, Sir Tony Hoare describes implementing null references as a part of the ALGOL programming languag…

[转载] 什么是Java中的自动拆装箱 integer

参考链接&#xff1a; Java中autoboxing自动装箱整数对象的比较 本文主要介绍Java中的自动拆箱与自动装箱的有关知识。 1、基本数据类型 基本类型&#xff0c;或者叫做内置类型&#xff0c;是Java中不同于类(Class)的特殊类型。它们是我们编程中使用最频繁的类型。 Jav…

[转载] python常用库

参考链接&#xff1a; Python–新一代语言 转载至&#xff1a;https://www.cnblogs.com/jiangchunsheng/p/9275881.html 今天我将介绍20个属于我常用工具的Python库&#xff0c;我相信你看完之后也会觉得离不开它们。他们是&#xff1a; Requests.Kenneth Reitz写的最富盛…

linux下安装配置oracle

检查系统是否已安装所需的开发包 使用rpm -qa命令&#xff0c;确保以下包已成功安装。对于包的版本,只有版本高于下面的都可以,如果低于此版本,则要升级处理,如下: binutils-2.15.92.0.2-13.EL4 compat-db-4.1.25-9 compat-libstdc-296-2.96-132.7.2 control-center-2.8.0-12 g…

[转载] c++多态与java多态性_Java中的多态性

参考链接&#xff1a; Java中的加法和串联 c多态与java多态性 Polymorphism is one of the core concepts of OOPS paradigm. The meaning of polymorphism is the condition of occurring in several different forms. 多态是OOPS范式的核心概念之一。 多态性的含义是以几种不…

USB peripherals can turn against their users

Turning USB peripherals into BadUSB USB devices are connected to – and in many cases even built into – virtually all computers. The interface standard conquered the world over the past two decades thanks to its versatility: Almost any computer peripheral…

[转载] JAVA条件表达式的陷阱

参考链接&#xff1a; Java条件表达式中的数字类型提升 Map<String, Integer> map new HashMap<String, Integer>(); map.put("count", null); Integer it map null ? 0 : map.get("count"); 注意&#xff1a;在第三行&#xff0c;会…

Linux系统管理初步(七)系统服务管理、chkconfig与systemd 编辑中

Linux系统本身包含了很多服务&#xff0c;CentOS6之前系统的服务用SysV控制&#xff0c;CentOS7改为systemd控制 一、chkconfig服务管理机制 简而言之&#xff0c;chkconfig就是CentOS6以前用来控制系统服务的工具&#xff0c; 常用方法举例 chkconfig --list #列出所有的系统服…

[转载] 菜鸟举例理解字节流和字符流区别

参考链接&#xff1a; Java中的字符流与字节流 Character Stream对比Byte Stream 菜鸟举例理解字节流和字符流区别 按照uft8编码方式存储文档 文档存储路径在D盘下 /** * 按照utf8格式存储文档 */ public static void storeDataByUTF8(){ String path "D:" …

[转载] Java9发布回顾Java 8的十大新特性

参考链接&#xff1a; Java中的DoubleStream mapToObj() java9已经在北京时间9月22日正式发布&#xff0c;开发者可以在oracle jdk官网上下载到最新的jdk9。 今天&#xff0c;我们先来一起复习一下2014年发布的Java 8的十大新特性。先来喝杯java~~~ 按照java升级的传统&…

窗体间传递数据

前言 做项目的时候&#xff0c;winfrom因为没有B/S的缓存机制&#xff0c;窗体间传递数据没有B/S页面传递数据那么方便&#xff0c;今天我们就说下winfrom中窗体传值的几种方式。 共有字段传递 共有字段传递实现起来很方便&#xff0c;就是在窗体类中加个共有字段属性&#xff…

[转载] c语言中检查命令行参数_C中的命令行参数

参考链接&#xff1a; Java中的命令行参数 c语言中检查命令行参数 Command line argument is a parameter supplied to the program when it is invoked. Command line argument is an important concept in C programming. It is mostly used when you need to control your …

MySQL关闭Enterprise Server源码

今天从MySQL官方网站上获知&#xff0c;MySQL宣布关闭Enterprise Server的源码&#xff0c;对于广大开源爱好者来说&#xff0c;这是一个沉重的打击。虽然免费的用户群体一般仅仅使用MySQL Community Server&#xff08;开源免费社区版&#xff09;&#xff0c;但关闭MySQL Ent…

[转载] Java中Scanner用法总结

参考链接&#xff1a; Java之Scanner类 最近在做OJ类问题的时候&#xff0c;经常由于Scanner的使用造成一些细节问题导致程序不通过&#xff08;最惨的就是网易笔试&#xff0c;由于sc死循环了也没发现&#xff0c;导致AC代码也不能通过。。。&#xff09;&#xff0c;因此对S…

os和shutil模块

import os //os模块基本实现了linux系统中所有的命令 os.system(终端命令)&#xff1a;在终端执行命令 os.getcwd():获取当前的工作路径 os.chdir():修改工作路径 os.chmod():修改权限 os.chown():修改属主属组 os.mkdir():创建单个目录&#xff0c;当目录存在时报异常&…

[转载] JAVA语言程序设计(基础篇)第十版课后题答案(第一章)

参考链接&#xff1a; Java中的Scanner和nextChar() JAVA语言程序设计&#xff08;基础篇&#xff09;第十版课后题答案 第一章 第二题 /** Created by ysy on 2018/7/6. */ public class text2 { public static void main(String[] args){ for(int i 0; i < 5; i) Syste…