今天帮忙查bug发现了一个java中null值处理时候容易疏忽的问题,null值转换String类型时隐式的cast。
先看下null值在几个情景下的使用:
1.首先是控制台输出null值:
String str=null; System.out.println(str);
上面这行代码的执行结果控制台输出结果是null,查看println函数发现其中使用了这样一个逻辑
if (s == null) {
s = "null";
}
其实上面的语句在编译层面上与System.out.println((String)null)是等价的,只是通过对null值进行类型绑定避免了二义性(println(Object obj)/println(String str))。既然PrintStream重载了println(String str)、println(Object obj)我们也不难理解除去""和null本身含义的不一样的原因,统一使用字符串“null”作为对null的输出也保证了重载接口语义的一致性(null object返回空字符串很显然是不合理的)。
2.null值在+以及StringBuilder中的使用:
String str=""+null;
查看其对应的bytecode我们可以发现:
NEW java/lang/StringBuilder DUP INVOKESPECIAL java/lang/StringBuilder.<init>()V ACONST_NULL INVOKEVIRTUAL java/lang/StringBuilder.append(Ljava/lang/Object;)Ljava/lang/StringBuilder; INVOKEVIRTUAL java/lang/StringBuilder.toString()Ljava/lang/String;
其实String str=""+null与String str=new StringBuilder("").append((Object)null).toString();从编译层面并没有太大区别(当然使用“+”编译器会进行一些优化,另外“+null”编译器编译时使用的是append(Object obj)从而避免二义性)。StringBuilder.append()中对与null值的处理方式也是使用字符串“null”而非空字符串。
废话了那么多,无非证明了一点,null和“”除了在某些String比较的情况下等价,大部分场景我们都应该谨慎地使用(String)null。例如+null以及append(null)再使用时也很容易犯错,下面就是今天遇到的案例。
import java.util.HashMap; import java.util.Iterator; public class TestHashMap { public static void main(String[] args){ HashMap<String,String> hashMap=new HashMap<String,String>(); hashMap.put("a", null); hashMap.put("b", "b"); Iterator<String> iterator=hashMap.keySet().iterator(); StringBuilder sb=new StringBuilder(); while(iterator.hasNext()) { String key=iterator.next(); sb.append(key); sb.append(hashMap.get(key)); } System.out.println(sb.toString()); } }
返回的结果是b=ba=null,而不是我们期望的b=ba=,造成这个错误的原因根本上还是我们混淆了“”和null,想当然的认为append((String)null)的结果是空,总之要谨记null和”“是完全不相同的概念。
此外一些key value类型的数据结构,在toString的时候对“”和null的处理也是不一样的,例如:
org.apache.http.message.BasicNameValuePair
public String toString() { // don't call complex default formatting for a simple toString if (this.value == null) { return name; } else { int len = this.name.length() + 1 + this.value.length(); CharArrayBuffer buffer = new CharArrayBuffer(len); buffer.append(this.name); buffer.append("="); buffer.append(this.value); return buffer.toString(); } }
欢迎转载,但未经作者同意必须保留此段声明,且在文章页面明显位置给出原文连接。
相关推荐
总结来说,“JUnit使用札记”可能涵盖了如何创建和组织测试用例、如何利用JUnit注解来控制测试流程,以及如何结合实际的代码案例(如Sl330Case.java)来编写和运行测试。学习并熟练掌握JUnit对于任何Java开发者来说...
### JSP基础札记笔记 #### 第一讲:环境的配置 JSP(Java Server Pages)是一种基于Java技术的Web开发技术,用于创建动态网页。为了进行JSP开发,需要搭建相应的开发环境。 - **配置虚拟目录**:首先,需要创建一...
在"学习PMD软件中的札记"中,我们重点探讨了如何利用PMD来提升代码质量,并关注了`UseSingleton`规则。 `UseSingleton`是PMD中的一个规则,其目标是检测那些可以被设计为单例(Singleton)但当前并未如此实现的类。...
相比于高级语言如C++或Java,汇编语言与硬件交互更为直接,能够提供更高的控制精度和执行效率。Masm作为一款功能强大的汇编器,不仅支持x86架构,还支持x64架构,使得开发者能够在不同平台上编写出高性能的应用程序...
### JVM学习札记 #### 一、JVM运行机制 ##### 1、JVM的启动流程 JVM的启动过程主要包括以下步骤: 1. **加载配置文件**:JVM启动时,首先会根据当前路径寻找配置文件`JVM.CFG`,这个文件包含了JVM的一些基础设置...
《MINA使用札记——CumulativeProtocolDecoder使用详解》 MINA(Java Multithreaded Network Application Framework)是一个强大的、高性能的Java网络应用框架,它主要用于构建可伸缩的、高性能的服务端应用,如...
常见的框架有Java的Spring Boot、Python的Django或Flask、前端的React或Vue.js等。团队成员需要根据项目需求和技术栈来决定最适合的框架,并负责编写实现基础功能的代码,确保软件能够正常运行。 代码优化是提升...
描述中的“札记”表明这些笔记是以记录形式存在的,可能是课堂笔记、阅读摘录、实践经验和理解心得的集合。它们可能包含了讲师讲解的重点、示例代码、理论解释以及解决实际问题的方法。通过“来自代码研究员训练营的...
前端技术: ...Java:一种广泛用于后端开发的编程语言,常用于构建企业级应用。 Python:一种多用途编程语言,在Web开发中常用。 Ruby on Rails:一个基于Ruby编程语言的Web应用框架,提供了高效的开发工具。
札记本网站为阅读笔记,总结所有阅读将在102、201和301中进行,它具有标题和摘要链接代码301-中间软件开发代码301阅读笔记页面链接描述 响应式和浮动式 jQuery的柔性 网格 赫鲁库 Node.js原料药Java脚本Java脚本Java...
【JSP&Servlet学习札记】是一份详细记录了JavaServer Pages(JSP)和Servlet核心技术的学习笔记。这些技术是Web开发中的重要组成部分,尤其在企业级应用开发中广泛使用。下面将对JSP和Servlet的主要概念、核心功能...
这份手册的写作风格非常接近技术札记,不同于正式的书籍或手册。作者强调了笔记的实用性和个人特色,它更适合那些已经具备一定编程背景、特别是有Java经验的开发者,想要快速入门Clojure的人。 Clojure Handbook的...
JavaMail 是一个开源的Java库,它为Java程序员提供了处理电子邮件的能力。这个“javaMail.zip”文件包含了必要的jar包,使开发者能够在Java应用程序中实现发送邮件的功能。在JavaMail API的帮助下,开发人员可以轻松...
札记的形式使得内容更加聚焦于关键点和理解难点,帮助读者更好地消化和吸收编程知识。 在深入阅读和理解代码的过程中,有几个重要的知识点是不容忽视的: 1. **编程基础**:这是所有程序员的起点,包括基本语法、...
札记 技术要点: RPC: 登录及权限操作redis + session处理 搜索文章基于elasticsearch (内存不够了,暂停使用☻) 评论和关注等消息基于activemq: 数据结果处理: 开发: master采用的是rpc的微服务架构。 正常...
后端可能使用Node.js(Express或Koa)、Python(Django或Flask)、Java(Spring Boot)等语言进行开发。后端主要负责处理前端请求,调用天气API,进行数据处理,并将结果返回给前端。此外,后端还可能实现了用户认证...