Java中的NullPointerException是咱們最常常遇到的異常了,那咱們到底應該如何在編寫代碼是防患於未然呢。下面咱們就從幾個方面來入手,解決這個棘手的問題吧。java
值得慶幸的是,經過應用一些防護性編碼技術並遵循應用程序多個部分之間的約定,您能夠在必定程度上避免Java中的NullPointerException。程序員
順便說一下,在本文中,咱們將學習一些Java的編碼技術和最佳實踐,這些技巧和最佳實踐可用於避免的Java中的空指針異常。遵循這些Java的技巧還能夠最大程度地減小不少Java代碼中的 x !=NULL 檢查。面試
做爲經驗豐富的Java的程序員,您可能已經知道其中一些技巧,而且已經在項目中遵循了這些技巧,可是對於新手和中級 發人員來講,這多是個不錯的學習機會。順便說一句,若是您知道其餘避免Java中的NullPointerException並減小的Java中的空檢查的Java的技巧,請與咱們分享。算法
這些都是簡單的技術,很容易遵循,可是對代碼質量和健壯性有重大影響。以個人經驗,僅第一個技巧就能夠顯着提升代碼質量。如前所述,若是您知道任何其餘Java技巧或最佳實踐,能夠幫助減小空檢查,那麼能夠經過評論本文與咱們分享。數據庫
始終在不爲null的已知字符串上調用equals()方法。因爲equals()方法的方法是對稱的,調用a.equals(b)與調用b.equals(a)是同樣的,這就是爲何不少程序員不注意對象a和b。若是調用者爲空,則此調用的一個反作用就是可能致使NullPointerException。編程
Object unknownObject = null; //錯誤的方式 - 可能引發NullPointerException if(unknownObject.equals("knownObject")){ System.err.println("This may result in NullPointerException if unknownObject is null"); } //正確的方式 - 若是unknownObject爲null避免 NullPointerException if("knownObject".equals(unknownObject)){ System.err.println("better coding avoided NullPointerException"); }
這是避免NullPointerException的最簡單的Java技巧或最佳實踐,可是因爲equals()是一種常見方法,所以帶來了極大的改進 。數組
因爲在 null對象上調用toString()會引起NullPointerException ,所以,若是咱們能夠經過調用valueOf()得到相同的值, 則最好這樣作,由於將null傳遞給valueOf()會返回「 null 」,特別是在諸如Integer ,Float ,Double 這樣的包裝類的狀況下或BigDecimal 。安全
BigDecimal bd = getPrice(); System.out.println(String.valueOf(bd)); /不會拋出NPE System.out.println(bd.toString()); //在main線程拋出java.lang.NullPointerException"異常
若是不肯定對象是否爲null,請遵循此Java技巧。ide
有不少這樣開源庫,這些庫爲您檢查空作了大量工做。最多見的一種來自Apache Common 的StringUtils。您可使用StringUtils.isBlank() ,ISNUMERIC() ,isWhiteSpace()和其餘實用程序方法,而沒必要擔憂NullPointerException 。工具
//StringUtils中的方法是空指針安全的, 它不會出現NullPointerException System.out.println(StringUtils.isEmpty(null)); System.out.println(StringUtils.isBlank(null)); System.out.println(StringUtils.isNumeric(null)); System.out.println(StringUtils.isAllUpperCase(null));
輸出結果:
true true false false
可是,在使用庫方法以前,請不要忘記閱讀Null安全方法和類的文檔。這是另外一種Java最佳實踐,不須要太多的時間,但能夠帶來很大的改進。
Joshua Bloch在他的書《Effective Java》中也提到了Java最佳實踐或技巧,從這本書中你將得到更多的Java編程技巧。在公衆號【Java知己】,後臺回覆:Effective Java,能夠得到該書籍的連接。
經過返回空集合或空數組,您能夠確保基本調用(如size(),length())不會因NullPointerException異常而失敗。集合類提供方便的空的List, Set 和Map方法:Collections.EMPTY_LIST ,Collections.EMPTY_SET 和Collections.EMPTY_MAP ,能夠相應地使用它們。這是代碼示例
public List getOrders(Customer customer){ List result = Collections.EMPTY_LIST; return result; }
一樣,您可使用Collections.EMPTY_SET 和Collections.EMPTY_MAP 而不是返回null。
在編寫方法時,能夠經過使用@NotNull 和@Nullable 這樣的註釋來聲明方法是否爲null安全,從而定義有關可空性的契約。 現代的編譯器,IDE或工具能夠讀取此批註並幫助您進行缺失的空檢查,或者能夠通知您沒必要要的空檢查,這會使您的代碼混亂。
IntelliJ IDE 和FindBugs的已經支持這種註釋。這些註釋也是JSR 305的一部分,可是即便在沒有任何工具或IDE支持的狀況下,此註釋自己也能夠做爲文檔使用。經過查看 @NotNull 和@Nullable ,程序員本身能夠決定是否檢查null。順便說一句,對於Java程序員來講,這是相對較新的最佳實踐,要花些時間才能被利用起來。
儘管存在其餘缺點,例如建立臨時對象,但若是包裝類對象爲null,則自動裝箱也容易發生NullPointerException 。例如, 若是人員沒有電話號碼,則如下代碼將失敗,會NullPointerException ,而不是返回null 。
Person ram = new Person("ram"); int phone = ram.getPhone();
若是與自動裝箱和拆箱一塊兒使用,既也會引起NullPointerException 。
在Java的中避免NullPointerException異常的最佳方法之一就是定義初始值並遵循約定。大多數NullPointerException異常發生的緣由是使用不完整的信息建立對象或未提供全部必需的依賴關係。若是您不容許建立不完整的對象並優雅地拒絕任何此類請求,則能夠防止不少NullPointerException 的出現。一樣,若是 容許建立對象,則應該使用合理的替代值。例如,若是沒有id 和name ,則不能建立Employee 對象 ,可是能夠具備可選的電話號碼。如今,若是員工沒有電話號碼而不是返回零,不然返回默認值,例如零,可是必須謹慎地選擇該選項,踩在某些時候檢查null很容易,而不是撥打無效號碼。一個相同的註釋,經過定義什麼能夠爲空和什麼不能爲空,調用者能夠作出明智的決定。選擇fast-fail仍是接受null也是您須要採起並堅持一致的重要設計方法。
客戶,訂單等領域對象,則應在數據庫自己上定義空值約束。因爲數據庫能夠從多個來源獲取數據,所以在DB中進行空能力檢查將確保數據完整性。保持數據庫的空約束也將有助於減小_Java代碼中的空檢查_。從數據庫加載對象時,您將肯定其中一部分能夠爲null以及其中部分不爲null,這將最大程度地減小代碼中的的 !=null 檢查。
這是避免Java中的NullPointerExcpetion的另外一種方法。若是某個方法返回一個對象,該對象將在調用方上執行,例如Collection.iterator()方法返回Iterator,則調用方將在該迭代器上執行遍歷。假設調用者沒有任何繼承器,則能夠返回Null對象而不是null。Null對象是一個特殊的對象,在不一樣的其中中具備不一樣的含義,例如,在此處,調用hasNext()並返回false 的空Iterator 能夠是null對象。相似地,對於返回容器或集合類型的方法,應使用空對象而不是返回null。我打算寫一篇關於空對象模式,在這裏我將分享Java中空對象的更多示例。
夥計們,這些都是容易理解的Java技巧和最佳實踐,能夠避免NullPointerException。您將不費吹灰之力就能夠知道這些技巧有多有用。若是您要使用其餘任何技巧來避免此例外(不在此列表中) ),則請經過評論與咱們分享,我將在此處後續更新。
「不積跬步,無以致千里」,但願將來的你能:有夢爲馬 隨處可棲!加油,少年!
關注公衆號:「Java 知己」,天天更新Java知識哦,期待你的到來!