Java中有關Null的9件事
對於Java程式設計師來說,null是令人頭痛的東西。時常會受到空指標異常(NPE)的騷擾。連Java的發明者都承認這是他的一項巨大失誤。Java為什麼要保留null呢?null出現有一段時間了,並且我認為Java發明者知道null與它解決的問題相比帶來了更多的麻煩,但是null仍然陪伴著Java。
我越發感到驚奇,因為java的設計原理是為了簡化事情,那就是為什麼沒有浪費時間在指標、操作符過載、多繼承實現的原因,null卻與此正好相反。好吧,我真的不知道這個問題的答案,我知道的是不管null被Java開發者和開源社群如何批評,我們必須與null共同存在。與其為null的存在感到後悔,我們倒不如更好的學習null,確保正確使用null。
為什麼在Java中需要學習null?因為如果你對null不注意,Java將使你遭受空指標異常的痛苦,並且你也會得到一個沉痛的教訓。精力充沛的程式設計是一門藝術,你的團隊、客戶和使用者將會更加欣賞你。以我的經驗來看,導致空指標異常的一個最主要的原因是對Java中null的知識還不夠。你們當中的很多已經對null很熟悉了,但是對那些不是很熟悉的來說,可以學到一些關於null老的和新的知識。讓我們一起重新學習Java中null的一些重要知識吧。
Java中的Null是什麼?
正如我說過的那樣,null是Java中一個很重要的概念。null設計初衷是為了表示一些缺失的東西,例如缺失的使用者、資源或其他東西。但是,一年後,令人頭疼的空指標異常給Java程式設計師帶來不少的騷擾。在這份材料中,我們將學習到Java中null關鍵字的基本細節,並且探索一些技術來儘可能的減少null的檢查以及如何避免噁心的空指標異常。
1)首先,null是Java中的關鍵字,像public、static、final。它是大小寫敏感的,你不能將null寫成Null或NULL,編譯器將不能識別它們然後報錯。
Object obj = NULL; // Not Ok Object obj1 = null //Ok
2)就像每種原始型別都有預設值一樣,如int預設值為0,boolean的預設值為false,null是任何引用型別的預設值,不嚴格的說是所有object型別的預設值。就像你建立了一個布林型別的變數,它將false作為自己的預設值,Java中的任何引用變數都將null作為預設值。這對所有變數都是適用的,如成員變數、區域性變數、例項變數、靜態變數(但當你使用一個沒有初始化的區域性變數,編譯器會警告你)。為了證明這個事實,你可以通過建立一個變數然後列印它的值來觀察這個引用變數,如下圖程式碼所示:
private static Object myObj; public static void main(String args[]){ System.out.println("What is value of myObjc : " + myObj); }
What is value of myObjc : null
這對靜態和非靜態的object來說都是正確的。就像你在這裡看到的這樣,我將myObj定義為靜態引用,所以我可以在主方法裡直接使用它。注意主方法是靜態方法,不可使用非靜態變數。
3)我們要澄清一些誤解,null既不是物件也不是一種型別,它僅是一種特殊的值,你可以將其賦予任何引用型別,你也可以將null轉化成任何型別,來看下面的程式碼:
String str = null; // null can be assigned to String Integer itr = null; // you can assign null to Integer also Double dbl = null; // null can also be assigned to Double String myStr = (String) null; // null can be type cast to String Integer myItr = (Integer) null; // it can also be type casted to Integer Double myDbl = (Double) null; // yes it's possible, no error
4)null可以賦值給引用變數,你不能將null賦給基本型別變數,例如int、double、float、boolean。如果你那樣做了,編譯器將會報錯,如下所示:
int i = null; // type mismatch : cannot convert from null to int short s = null; // type mismatch : cannot convert from null to short byte b = null: // type mismatch : cannot convert from null to byte double d = null; //type mismatch : cannot convert from null to double Integer itr = null; // this is ok int j = itr; // this is also ok, but NullPointerException at runtime
5) 任何含有null值的包裝類在Java拆箱生成基本資料型別時候都會丟擲一個空指標異常。一些程式設計師犯這樣的錯誤,他們認為自動裝箱會將null轉換成各自基本型別的預設值,例如對於int轉換成0,布林型別轉換成false,但是那是不正確的,如下面所示:
Integer iAmNull = null; int i = iAmNull; // Remember - No Compilation Error
import java.util.HashMap; import java.util.Map; /** * An example of Autoboxing and NullPointerExcpetion * * @author WINDOWS 8 */ public class Test { public static void main(String args[]) throws InterruptedException { Map numberAndCount = new HashMap<>(); int[] numbers = {3, 5, 7,9, 11, 13, 17, 19, 2, 3, 5, 33, 12, 5}; for(int i : numbers){ int count = numberAndCount.get(i); numberAndCount.put(i, count++); // NullPointerException here } } }
輸出:
Exception in thread "main" java.lang.NullPointerException at Test.main(Test.java:25)
這段程式碼看起來非常簡單並且沒有錯誤。你所做的一切是找到一個數字在陣列中出現了多少次,這是Java陣列中典型的尋找重複的技術。開發者首先得到以前的數值,然後再加一,最後把值放回Map裡。程式設計師可能會以為,呼叫put方法時,自動裝箱會自己處理好將int裝箱成Interger,但是他忘記了當一個數字沒有計數值的時候,HashMap的get()方法將會返回null,而不是0,因為Integer的預設值是null而不是0。當把null值傳遞給一個int型變數的時候自動裝箱將會返回空指標異常。設想一下,如果這段程式碼在一個if巢狀裡,沒有在QA環境下執行,但是你一旦放在生產環境裡,BOOM:-)
6)如果使用了帶有null值的引用型別變數,instanceof操作將會返回false:
Integer iAmNull = null; if(iAmNull instanceof Integer){ System.out.println("iAmNull is instance of Integer"); }else{ System.out.println("iAmNull is NOT an instance of Integer"); }
輸出:
i
AmNull is NOT an instance of Integer
這是instanceof操作一個很重要的特性,使得對型別強制轉換檢查很有用
7)你可能知道不能呼叫非靜態方法來使用一個值為null的引用型別變數。它將會丟擲空指標異常,但是你可能不知道,你可以使用靜態方法來使用一個值為null的引用型別變數。因為靜態方法使用靜態繫結,不會丟擲空指標異常。下面是一個例子:
public class Testing { public static void main(String args[]){ Testing myObject = null; myObject.iAmStaticMethod(); myObject.iAmNonStaticMethod(); } private static void iAmStaticMethod(){ System.out.println("I am static method, can be called by null reference"); } private void iAmNonStaticMethod(){ System.out.println("I am NON static method, don't date to call me by null"); }
輸出:
I am static method, can be called by null reference Exception in thread "main" java.lang.NullPointerException at Testing.main(Testing.java:11)
8)你可以將null傳遞給方法使用,這時方法可以接收任何引用型別,例如public void print(Object obj)可以這樣呼叫print(null)。從編譯角度來看這是可以的,但結果完全取決於方法。Null安全的方法,如在這個例子中的print方法,不會丟擲空指標異常,只是優雅的退出。如果業務邏輯允許的話,推薦使用null安全的方法。
9)你可以使用==或者!=操作來比較null值,但是不能使用其他演算法或者邏輯操作,例如小於或者大於。跟SQL不一樣,在Java中null==null將返回true,如下所示:
public class Test { public static void main(String args[]) throws InterruptedException { String abc = null; String cde = null; if(abc == cde){ System.out.println("null == null is true in Java"); } if(null != null){ System.out.println("null != null is false in Java"); } // classical null check if(abc == null){ // do something } // not ok, compile time error if(abc > null){ } } }
輸出:
null == null is true in Java
這是關於Java中null的全部。通過Java程式設計的一些經驗和使用簡單的技巧來避免空指標異常,你可以使你的程式碼變得null安全。因為null經常作為空或者未初始化的值,它是困惑的源頭。對於方法而言,記錄下null作為引數時方法有什麼樣的行為也是非常重要的。總而言之,記住,null是任何一個引用型別變數的預設值,在java中你不能使用null引用來呼叫任何的instance方法或者instance變數。
相關文章
- Java中有關stringJava
- java中有關日期的顯示問題 (轉)Java
- 關於 Java 你不知道的 10 件事Java
- Java--- 關於null的處理若干方法JavaNull
- 記Java中有關記憶體的簡單認識Java記憶體
- Java 中關於 null 物件的容錯處理JavaNull物件
- 關於Java垃圾回收被誤解的7件事Java
- 關於NULLNull
- JavaScript中有關new的問題JavaScript
- 關於 Java 物件序列化您不知道的 5 件事Java物件
- 面試題((A)null).fun()——java中null值的強轉面試題NullJava
- 關於Java效能的9個謬論Java
- C#中有關屬性的演示C#
- 關於 Java Collections API 您不知道的 5 件事,第 1 部分JavaAPI
- 關於 oracle NULLOracleNull
- 軟體工程師必學的9件事軟體工程工程師
- 請問之前《資料》中有關於flash+java的技術的介紹Java
- ORACLE關於NULL的總結OracleNull
- 和Null有關的函式Null函式
- null in ABAP and nullpointer in JavaNullJava
- 你不知道Java的10件事Java
- C#中有關方法的宣告和呼叫C#
- java反射中有哪些APIJava反射API
- java中有哪些基本註解Java
- 軟體工程師應該知道的9件事軟體工程工程師
- 關於NULL的兩個計算Null
- 關於null值的小知識Null
- oracle中關於null的定義OracleNull
- SQL中關於NULL的程式碼SQLNull
- Java null最佳實踐JavaNull
- 不願看到Java開發者再做的10件事Java
- C#中有關異常的捕獲演示C#
- C#中有關欄位的訪問控制C#
- 讓程式設計師精神分裂的9件事程式設計師
- Java 20中有哪些新功能? - symflowerJava
- Java 7中有什麼?Java
- 關於MongoDB你需要知道的幾件事MongoDB
- SQL 語句中關於 NULL 的那些坑SQLNull