Java中避免空指針的幾種方法解析
前言
Java 編程中哪個異常是你印象最深刻的,那 NullPointerException 空指針可以說是臭名昭著的。不要說初級程序員會碰到,即使是中級,專家級程序員稍不留神,就會掉入這個坑里。
Java 中任何對象都有可能為空,當我們調(diào)用空對象的方法時就會拋出 NullPointerException 空指針異常,這是一種非常常見的錯誤類型。我們可以使用若干種方法來避免產(chǎn)生這類異常,使得我們的代碼更為健壯。
空指針出現(xiàn)的幾種情況
1、調(diào)用了空對象的實例方法
public class Person { // 屬性 private String name; private int age; public void print(){ System.out.println("This is Person Class"); } public String read(){ System.out.println("This is person read"); return null; } public static void main(String[] args) { Person person = null; //調(diào)用了空對象的實例方法 person.print(); } }
2、訪問了空對象的屬性
Person person = null; //調(diào)用了空對象的屬性 System.out.println(person.age);
3、當數(shù)組是一個空對象時,取它的長度
Person person = null; //當數(shù)組是一個空對象時,取它的長度 System.out.println(person.name.length());
4、方法的返回值是 null, 調(diào)用方直接去使用
Person person = new Person(); //方法的返回值是 null, 調(diào)用方直接去使用 System.out.println(person.read().contains("Java"));
如何從根源避免空指針
1、使用之前一定要初始化,或檢查是否初始化;
2、盡量避免在函數(shù)中返回 NULL, 或給出詳細的注釋;
3、外部傳值,除非有明細的說明,否則,一定要判斷是否為 NULL。
equals和equalsIgnoreCase()方法
Object類中的equals 方法在非空對象引用上實現(xiàn)相等關(guān)系,具有對稱性 x.equals(y) 和 y.equals(x) 結(jié)果是一樣的,但當x == null時會拋出空指針異常。
例如:
String x = null; String y = "world"; if(x.equals(y)){ // java.lang.NullPointerException } if(y.equals(x)){//即便 x 是 null也能避免 NullPointerException }
所以我們要把確定不為null的對象或值放在前面。
valueOf()和toString()
調(diào)用null對象的toString()會拋出空指針異常,使用valueOf()可以獲得相同的值,傳遞一個 null 給 valueOf() 將會返回null。尤其是在那些包裝類,像Integer、Float、Double和BigDecimal。
例如:
Integer i = null; System.out.println(i.toString()); // 拋出NullPointerException異常 System.out.println(String.valueOf(i)); // 返回 null不會出現(xiàn)異常
Optional 類型
Java 8 引入了 Optional 類型,我們可以用它來對函數(shù)的返回值進行包裝。這種方式的優(yōu)點是可以明確定義該方法是有可能返回空值的,因此調(diào)用方必須做好相應(yīng)處理,這樣也就不會引發(fā)空指針異常。但是,也不可避免地需要編寫更多代碼,而且會產(chǎn)生很多垃圾對象,增加 GC 的壓力,因此在使用時需要酌情考慮。
在業(yè)務(wù)系統(tǒng)中,對象中嵌套對象是經(jīng)常發(fā)生的場景,如下示例代碼:
// 最外層對象 class Outer { Nested nested; Nested getNested() { return nested; } } // 第二層對象 class Nested { Inner inner; Inner getInner() { return inner; } } // 最底層對象 class Inner { String foo; String getFoo() { return foo; } }
業(yè)務(wù)中,假設(shè)我們需要獲取 Outer 對象對底層的 Inner 中的 foo 屬性,我們必須寫一堆的非空校驗,來防止發(fā)生 NullPointerException:
// 繁瑣的代碼 Outer outer = new Outer(); if (outer != null && outer.nested != null && outer.nested.inner != null) { System.out.println(outer.nested.inner.foo); }
在 Java8 中,我們有更優(yōu)雅的解決方式,那就是使用 Optional是說,我們可以在一行代碼中,進行流水式的 map 操作。而 map 方法內(nèi)部會自動進行空校驗:
Optional.of(new Outer()) .map(Outer::getNested) .map(Nested::getInner) .map(Inner::getFoo .ifPresent(System.out::println); // 如果不為空,最終輸出 foo 的值
suppiler 函數(shù)自定義增強 API
我們可以利用 suppiler 函數(shù)來出一個終極解決方案:
public static <T> Optional<T> resolve(Supplier<T> resolver) { try { T result = resolver.get(); return Optional.ofNullable(result); } catch (NullPointerException e) { // 可能會拋出空指針異常,直接返回一個空的 Optional 對象 return Optional.empty(); } }
利用上面的 resolve 方法來重構(gòu)上述的非空校驗代碼段:
Outer obj = new Outer(); // 直接調(diào)用 resolve 方法,內(nèi)部做空指針的處理 resolve(() -> obj.getNested().getInner().getFoo()); .ifPresent(System.out::println); // 如果不為空,最終輸出 foo 的值
使用null安全的方法和庫
有很多開源庫已經(jīng)為您做了繁重的空指針檢查工作。其中最常用的一個的是Apache commons 中的StringUtils。你可以使用StringUtils.isBlank(),isNumeric(),isWhiteSpace()以及其他的工具方法而不用擔心空指針異常。
//StringUtils方法是空指針安全的,他們不會拋出空指針異常 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
斷言
斷言是用來檢查程序的安全性的,在使用之前進行檢查條件,如果不符合條件就報異常,符合就繼續(xù)。
Java 中自帶的斷言關(guān)鍵字:assert,如:
assert name == null : "名稱不能為空";
輸出:
Exception in thread "main" java.lang.AssertionError: 名稱不正確
不過默認是不啟動斷言檢查的,需要要帶上 JVM 參數(shù):-enableassertions 才能生效。
Java 中這個用的很少,建議使用 Spring 中的,更強大,更方便好用。
Spring中的用法:
Assert.notNull(name,"名稱不能為空");
創(chuàng)建返回空集合而不是null的方法
一個非常好的技術(shù)是創(chuàng)建返回一個空集合的方法,而不是一個null值。你的應(yīng)用程序的代碼可以遍歷空集合并使用它的方法和字段,而不會拋出一個NullPointerException。Collections類提供了方便的空 List,Set 和 Map: Collections.EMPTY_LIST,Collections.EMPTY_SET,Collections.EMPTY_MAP。
例如:
public class Example { private static List<Integer> numbers = null; public static List<Integer> getList() { if (numbers == null){ return Collections.EMPTY_LIST; } else { return numbers; } } }
賦值時自動拆箱出現(xiàn)空指針
1、變量賦值自動拆箱出現(xiàn)的空指針
Long i = null; //變量賦值自動拆箱出現(xiàn)的空指針 long j = i;
Long 自動拆箱為 long 實質(zhì)是調(diào)用了 longValue 方法,由于以上的 Long 類型變量值為 null,自動拆箱就會報 NPE。
2、方法傳參時自動拆箱引起空指針異常
public static int add(int x, int y) { return x + y; } public static void main(String[] args) { Integer left = null; Integer right = null; //方法傳參時自動拆箱引起空指針異常 System.out.println(add(left, right)); }
以上自動拆箱報 NPE,原因在于裝箱的值為 null,調(diào)用 null 的任何 方法都會報錯。
規(guī)避指南:
- 基本數(shù)據(jù)類型優(yōu)于包裝器類型,優(yōu)先考慮使用基本類型。對于不確定的包裝器類型,一定要校驗是否為 NULL。
- 基本數(shù)據(jù)類型比包裝器類型更加節(jié)省時間與空間。
小結(jié)
關(guān)于怎么有效避免空指針,其實還有更多,如何避免空指針,一是要注意代碼編寫規(guī)范,二是要提高代碼素養(yǎng)。
到此這篇關(guān)于Java中避免空指針的幾種方法解析的文章就介紹到這了,更多相關(guān)Java避免空指針內(nèi)容請搜索腳本之家以前的文章或繼續(xù)瀏覽下面的相關(guān)文章希望大家以后多多支持腳本之家!
相關(guān)文章
利用java和sqlserver建立簡易圖書管理系統(tǒng)的完整步驟
圖書館管理系統(tǒng)是圖書館管理工作中不可缺少的部分,它對于圖書館的管理者和使用者都非常重要,下面這篇文章主要給大家介紹了關(guān)于利用java和sqlserver建立簡易圖書管理系統(tǒng)的完整步驟,需要的朋友可以參考下2022-06-06SpringBoot使用Mybatis&Mybatis-plus文件映射配置方法
這篇文章主要介紹了SpringBoot使用Mybatis&Mybatis-plus文件映射配置方法,本文給大家介紹的非常詳細,對大家的學習或工作具有一定的參考借鑒價值,需要的朋友可以參考下2021-05-05List集合中對數(shù)據(jù)實現(xiàn)多重規(guī)則進行排序的案例
今天小編就為大家分享一篇關(guān)于List集合中對數(shù)據(jù)實現(xiàn)多重規(guī)則進行排序的案例,小編覺得內(nèi)容挺不錯的,現(xiàn)在分享給大家,具有很好的參考價值,需要的朋友一起跟隨小編來看看吧2018-12-12Struts2+Hibernate實現(xiàn)數(shù)據(jù)分頁的方法
這篇文章主要介紹了Struts2+Hibernate實現(xiàn)數(shù)據(jù)分頁的方法,結(jié)合實例形式分析了Struts2結(jié)合Hibernate實現(xiàn)數(shù)據(jù)分頁的原理,步驟與相關(guān)實現(xiàn)代碼,需要的朋友可以參考下2016-03-03