Java札记(二)

       今天帮忙查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();
        }
    } 

 

  欢迎转载,但未经作者同意必须保留此段声明,且在文章页面明显位置给出原文连接。

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值