今天帮忙查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();
}
}
欢迎转载,但未经作者同意必须保留此段声明,且在文章页面明显位置给出原文连接。