日韩性视频-久久久蜜桃-www中文字幕-在线中文字幕av-亚洲欧美一区二区三区四区-撸久久-香蕉视频一区-久久无码精品丰满人妻-国产高潮av-激情福利社-日韩av网址大全-国产精品久久999-日本五十路在线-性欧美在线-久久99精品波多结衣一区-男女午夜免费视频-黑人极品ⅴideos精品欧美棵-人人妻人人澡人人爽精品欧美一区-日韩一区在线看-欧美a级在线免费观看

歡迎訪問 生活随笔!

生活随笔

當前位置: 首頁 > 编程语言 > java >内容正文

java

Java 中关于 null 对象的容错处理

發布時間:2025/3/21 java 24 豆豆
生活随笔 收集整理的這篇文章主要介紹了 Java 中关于 null 对象的容错处理 小編覺得挺不錯的,現在分享給大家,幫大家做個參考.

在 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 對象不會拋出異常?帶著這個疑問,我開始了解惑之旅。下面我將詳細闡述我解決這個問題的思路,并且深入 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 對象分開進行處理。

String 對象:直接判斷是否為 null,如果為 null 給 null 對象賦值為”null”。

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

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

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

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

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

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

結果可能你也猜到了:

null!

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

L0LINENUMBER?27?L0ACONST_NULLASTORE?1 L1LINENUMBER?28?L1NEW?java/lang/StringBuilderDUPINVOKESPECIAL?java/lang/StringBuilder.<init>?()VALOAD?1INVOKEVIRTUAL?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 L2LINENUMBER?29?L2GETSTATIC?java/lang/System.out?:?Ljava/io/PrintStream;ALOAD?1INVOKEVIRTUAL?java/io/PrintStream.print?(Ljava/lang/String;)V

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

編譯器對字符串相加會進行優化,首先實例化一個StringBuilder,然后把相加的字符串按順序append,最后調用toString返回一個String對象。不信你們看看上面的字節碼是不是出現了StringBuilder。詳細的解釋參考這篇文章 Java細節:字符串的拼接。

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”。

來源:http://blog.xiaohansong.com/2016/03/13/null-in-java-string/

總結

以上是生活随笔為你收集整理的Java 中关于 null 对象的容错处理的全部內容,希望文章能夠幫你解決所遇到的問題。

如果覺得生活随笔網站內容還不錯,歡迎將生活随笔推薦給好友。