其實 null 這個東西,真是讓人又愛又恨频丘,悲喜參半的東西办成。
用的好了,能表征很多狀態(tài)搂漠,并在程序中很好實現(xiàn)狀態(tài)的傳遞迂卢,用的不好了,各種NPE問題可以把你煩死……
好吧桐汤,以上是題外話而克,那么這次問題的主旨在于,鑒于null這種關鍵字很大程度上豐富了我們的語義怔毛,并且隨著JDK5之后裝箱和拆箱的自動進行员萍,null的出場概率更是越來越多。
但是隨之而來一個問題就是拣度,當我們想要打印一個null來表示該對象為null的時候碎绎,什么操作去處理才是安全可靠的呢?
本文的主旨主要就是對此做一個簡單的備忘抗果,以防之后模棱兩可的時候又要去看很久筋帖,畢竟好記性不如爛筆頭嘛,那么首先先把備忘的表格寫上(希望大家補充和指教~ :D)
方法 | 結果 |
---|---|
println(objectNull) | 成功打印null |
String.valueOf(objectNull) | 成功打印null |
StringBuider.append(objectNull) | 成功打印null |
ObjectNull = null; ObjectNull .toString() | NPE |
"any" + objectNull | 成功打印null |
以上就是一個簡單的表格總結冤馏,那么為什么會產生這種原因呢日麸?
具體原因分析
其實通過源碼來看,就會發(fā)現(xiàn)逮光,其實問題都非常的清晰了代箭,以下對每個操作類型都給出了實現(xiàn)的片段,來佐證實際程序中的操作結果涕刚。
println(objectNull)
可以發(fā)現(xiàn)嗡综,該函數(shù)內部對null做了特殊處理,如果是null對象則處理成一個“null”的字符串副女,從而不會造成NPE問題蛤高。
/**
* Prints a string. If the argument is <code>null</code> then the string
* <code>"null"</code> is printed. Otherwise, the string's characters are
* converted into bytes according to the platform's default character
* encoding, and these bytes are written in exactly the manner of the
* <code>{@link #write(int)}</code> method.
*
* @param s The <code>String</code> to be printed
*/
public void print(String s) {
if (s == null) {
s = "null";
}
write(s);
}
String.valueOf(objectNull)
/**
* Returns the string representation of the <code>Object</code> argument.
*
* @param obj an <code>Object</code>.
* @return if the argument is <code>null</code>, then a string equal to
* <code>"null"</code>; otherwise, the value of
* <code>obj.toString()</code> is returned.
* @see java.lang.Object#toString()
*/
public static String valueOf(Object obj) {
return (obj == null) ? "null" : obj.toString();
}
StringBuider.append(objectNull) :
雖然StringBuilder的append方法有比較多的重載方法,但是總體來說碑幅,都對null對象做了特殊的處理戴陡,方式主要有兩種:1.調用String.valueOf方法(具體實現(xiàn)原理如上所示);2.對null的字符串對象直接調整為打印“null”
// (筆者注): part1
public StringBuilder append(Object obj) {
return append(String.valueOf(obj));
}
// (筆者注): part2
/**
* Appends the specified string to this character sequence.
* <p>
* The characters of the {@code String} argument are appended, in
* order, increasing the length of this sequence by the length of the
* argument. If {@code str} is {@code null}, then the four
* characters {@code "null"} are appended.
* <p>
* Let <i>n</i> be the length of this character sequence just prior to
* execution of the {@code append} method. Then the character at
* index <i>k</i> in the new character sequence is equal to the character
* at index <i>k</i> in the old character sequence, if <i>k</i> is less
* than <i>n</i>; otherwise, it is equal to the character at index
* <i>k-n</i> in the argument {@code str}.
*
* @param str a string.
* @return a reference to this object.
*/
public AbstractStringBuilder append(String str) {
if (str == null) str = "null";
int len = str.length();
ensureCapacityInternal(count + len);
str.getChars(0, len, value, count);
count += len;
return this;
}
ObjectNull = null; ObjectNull .toString() :
如果沒有主動的重寫Object的toString方法沟涨,則會調用Object(所有類的父類)中的toString方法恤批,可見這種方法是沒有對null做特殊處理的,所以如果如Java中鼓勵的那樣裹赴,我們最好針對自己的對象重寫toString來避免這種NPE的問題喜庞。
其次,我們可以挑選裝箱類型來看一下棋返,也會發(fā)現(xiàn)延都,因為有自動拆箱的過程存在,也會存在NPE問題睛竣,所以這種場景下也需要注意晰房。
// object
public String toString() {
return getClass().getName() + "@" + Integer.toHexString(hashCode());
}
// Integer
public String toString() {
return toString(value);
}
"any" + objectNull :
參考這篇文章《在java中,字符串的加法是如何實現(xiàn)的射沟?》殊者,可以發(fā)現(xiàn)實際上這種加號的實現(xiàn)原理其實就是基于StringBuilder的,也就很好理解為什么加號會有這種表現(xiàn)了验夯。
小結
因此猖吴,使用toString的方式來打印null是存在問題的,而其它的幾種方式都得益于方法內部的兼容處理挥转,可以正常的處理null的打印海蔽。
特別有意思的是,+號的處理绑谣,實際上是通過StringBuilder來實現(xiàn)的准潭,不得不感慨一下這種復用思想的使用,結合java中string在堆中的實際處理情況來理解域仇,感覺也是一個非常有意思的處理方式刑然。