Java String 對 null 對象的容錯處理,stringnull

來源:互聯網
上載者:User

Java String 對 null 對象的容錯處理,stringnull
前言

最近在讀《Thinking in Java》,看到這樣一段話:

Primitives that are fields in a class are automatically initialized to zero, as noted in the Everything Is an Object chapter. But the object references are initialized to null, and if you try to call methods for any of them, you’ll get an exception-a runtime error. Conveniently, you can still print a null reference without throwing an exception.
大意是:原生類型會被自動初始化為 0,但是對象引用會被初始化為 null,如果你嘗試調用該對象的方法,就會拋出null 指標異常。通常,你可以列印一個 null 對象而不會拋出異常。

第一句相信大家都會容易理解,這是類型初始化的基礎知識,但是第二句就讓我很疑惑:為什麼列印一個 null 對象不會拋出異常?帶著這個疑問,我開始瞭解惑之旅。下面我將詳細闡述我解決這個問題的思路,並且深入 JDK 源碼找到問題的答案。

解決問題的過程

可以發現,其實這個問題有幾種情況,所以我們分類討論各種情況,看最後能不能得到答案。

首先,我們把這個問題分解為三個小問題,逐一解決。

第一個問題

直接列印 null 的 String 對象,會得到什麼結果?

String s = null;System.out.print(s);

啟動並執行結果是

null

果然如書上說的沒有拋出異常,而是列印了null。顯然問題的線索在於print函數的源碼中。我們找到print的源碼:


public void print(String s) {

    if (s == null) {

        s = "null";

    }

    write(s);

}

看到源碼才發現原來就只是加了一句判斷而已,簡單粗暴,可能你對 JDK 的簡單實現有點失望了。放心,第一個問題只是開胃菜而已,大餐還在後面。

第二個問題

列印一個 null 的非 String 對象,例如說 Integer:

Integer i = null;System.out.print(i);

啟動並執行結果不出意料:

null

我們再去看看print的源碼:


public void print(Object obj) {

    write(String.valueOf(obj));

}

有點不一樣的了,看來秘密藏在valueOf裡面。


public static String valueOf(Object obj) {

    return (obj == null) ? "null" : obj.toString();

}

看到這裡,我們終於發現了列印 null 對象不會拋出異常的秘密。print方法對 String 對象和非 String 對象分開進行處理。

  1. String 對象:直接判斷是否為 null,如果為 null 給 null 對象賦值為"null"

  2. 非 String 對象:通過調用String.valueOf方法,如果是 null 對象,就返回"null",否則調用對象的toString方法。

通過上面的處理,可以保證列印 null 對象不會出錯。

到這裡,本文就應該結束了。
什嗎?說好的大餐呢?上面還不夠塞牙縫呢。
開玩笑啦。下面我們來探討第三個問題。

第三個問題(隱藏的大餐)

null 對象與字串拼接會得到什麼結果?

String s = null;s = s + "!";System.out.print(s);

結果可能你也猜到了:

null!

為什麼呢?跟蹤代碼運行可以發現,這回跟print沒有什麼關係。但是上面的代碼就調用了print函數,不是它會是誰呢?+的嫌疑最大,但是+又不是函數,我們怎麼看到它的原始碼?這種情況,唯一的解釋就是編譯器動了手腳,天網恢恢,疏而不漏,找不到原始碼,我們可以去看看編譯器產生的位元組碼。


L0

 LINENUMBER 27 L0

 ACONST_NULL

 ASTORE 1

L1

 LINENUMBER 28 L1

 NEW java/lang/StringBuilder

 DUP

 INVOKESPECIAL java/lang/StringBuilder.<init> ()V

 ALOAD 1

 INVOKEVIRTUAL java/lang/StringBuilder.append (Ljava/lang/String;)Ljava/lang/StringBuilder;

 LDC "!"

 INVOKEVIRTUAL java/lang/StringBuilder.append (Ljava/lang/String;)Ljava/lang/StringBuilder;

 INVOKEVIRTUAL java/lang/StringBuilder.toString ()Ljava/lang/String;

 ASTORE 1

L2

 LINENUMBER 29 L2

 GETSTATIC java/lang/System.out : Ljava/io/PrintStream;

 ALOAD 1

 INVOKEVIRTUAL java/io/PrintStream.print (Ljava/lang/String;)V

看了上面的位元組碼是不是一頭霧水?這裡我們就要扯開話題,來侃侃+字串拼接的原理了。

編譯器對字串相加會進行最佳化,首先執行個體化一個StringBuilder,然後把相加的字串按順序append,最後調用toString返回一個String對象。不信你們看看上面的位元組碼是不是出現了StringBuilder


String s = "a" + "b";

//等價於

StringBuilder sb = new StringBuilder();

sb.append("a");

sb.append("b");

String s = sb.toString();

再回到我們的問題,現在我們知道秘密在StringBuilder.append函數的源碼中。


//針對 String 對象

public AbstractStringBuilder append(String str) {

    if (str == null)

        return appendNull();

    int len = str.length();

    ensureCapacityInternal(count + len);

    str.getChars(0, len, value, count);

    count += len;

    return this;

}

//針對非 String 對象

public AbstractStringBuilder append(Object obj) {

    return append(String.valueOf(obj));

}


private AbstractStringBuilder appendNull() {

    int c = count;

    ensureCapacityInternal(c + 4);

    final char[] value = this.value;

    value[c++] = 'n';

    value[c++] = 'u';

    value[c++] = 'l';

    value[c++] = 'l';

    count = c;

    return this;

}

現在我們恍然大悟,append函數如果判斷對象為 null,就會調用appendNull,填充"null"

總結

上面我們討論了三個問題,由此引出 Java 中 String 對 null 對象的容錯處理。上面的例子沒有覆蓋所有的處理情況,算是拋磚引玉。

如何讓程式中的 null 對象在我們的控制之中,是我們編程的時候需要時刻注意的事情。

Java團長

號:javatuanzhang

每日分享Java技術乾貨

長按識別二維碼

相關文章

聯繫我們

該頁面正文內容均來源於網絡整理,並不代表阿里雲官方的觀點,該頁面所提到的產品和服務也與阿里云無關,如果該頁面內容對您造成了困擾,歡迎寫郵件給我們,收到郵件我們將在5個工作日內處理。

如果您發現本社區中有涉嫌抄襲的內容,歡迎發送郵件至: info-contact@alibabacloud.com 進行舉報並提供相關證據,工作人員會在 5 個工作天內聯絡您,一經查實,本站將立刻刪除涉嫌侵權內容。

A Free Trial That Lets You Build Big!

Start building with 50+ products and up to 12 months usage for Elastic Compute Service

  • Sales Support

    1 on 1 presale consultation

  • After-Sales Support

    24/7 Technical Support 6 Free Tickets per Quarter Faster Response

  • Alibaba Cloud offers highly flexible support services tailored to meet your exact needs.