在寫程式碼的過程中,出現最多的異常可能就是空指標異常了。說白了,空指標異常就是你拿一個不存在的物件,去訪問它的成員屬性或者方法。我們暫且看下面的程式碼:
public static String getString() {
return null;
}
public static void main(String[] args) {
// 此處返回null
String str = getString();
System.err.println(str.length());
}
複製程式碼
很明顯,上面程式執行的結果肯定是排除煩人的java.lang.NullPointerException
:
Exception in thread "main" java.lang.NullPointerException
at org.springframework.web.SpringServletContainerInitializer.main(SpringServletContainerInitializer.java:187)
複製程式碼
但是,其實空指標本身並不是那麼可怕,可怕的是命名我們知道有這麼一種可能會出現空指標異常,但是我們卻不知道或者沒法提前預判,就像上面的程式碼片段,在eclipse IDE中是沒有任何提示的,如下圖:
那麼有什麼辦法我們可以提前預判到可能會丟擲NullPointerException
的程式碼塊,然後做防空處理呢!答案是肯定的。下面我將介紹幾種常見的防空方式,注意,這不是演習,這不是演習,這不是演習。哈哈!
- 1、使用註解方式標識引數、方法返回值是否為空
- 2、使用Java8提供的
Optional
類宣告我們的API
下面我將一一舉例進行探討(IDE以eclipse為例):
前置處理:
首先我們要在eclipse啟用基於註解的檢查,在Windows->Preference->Java->Compiler->Errors/Warnings->Null Analysis
,如下圖所示:
一、使用註解方式標識引數、方法返回值是否為空
JSR 303/305和Spring都提供了相應的的註解,如下所示:
- 1、JSR 303/305:
@Nonnull
、@Nullable
- 2、Spring:
@NonNull
、@Nullable
在eclipse啟動空檢驗之後,要想使上面的@Nullable
註解生效,還需要將註解的全路徑型別配置到上圖的Use default annotations for null sercifications
,配置如下圖:
配置完成之後,再看下面程式碼:
/**
* 表示返回的值可能為空
* @return
*/
@Nullable
public static String getString() {
return null;
}
/**
* 引數不能為空
* @param str
* @return
*/
public static String getName(@NonNull String str) {
return null;
}
public static void main(String[] args) {
// 此處返回null
String str = getString();
System.err.println(str.length());
// 引數為空
getName(null);
}
複製程式碼
這樣子可能為空的程式碼就一目瞭然了。當然了,其中的原理還是IDE支援掃描JSR規範的相關注解,Spring的@NonNull
、@Nullable
也是基於JSR註解實現的,可用於宣告方法,欄位或者引數。
二、Optional
Java8提供了對null進行建模的類,它叫Optional
。我們可以把它理解為一個容器,容器裡儲存的,可以是方法的放回值,也可以是方法引數值,如果方法返回值為null或者引數值為null,那麼就返回一個空容器物件。請看下面程式碼:
/**
* 表示返回的值可能為空
* @return
*/
public static Optional<String> getString() {
// 返回空容器,裡邊什麼也沒有
return Optional.empty();
}
/**
* 引數不能為空
* @param str
* @return
*/
public static String getName(Optional<String> str) {
return str.get();
}
public static void main(String[] args) {
// 此處返回Optional.empty()
Optional<String> optional = getString();
// 如果返回的是空容器,那麼就返回orElse的值,否則,返回容器裡的值
String value = optional.orElse("otherValue");
// 輸出otherValue
System.err.println(value);
// 引數為空
getName(Optional.of("value"));
}
複製程式碼
使用Optional
類很方便對可能返回null的值進行建模,同時Optional
裡邊提供了很多有用的方法允許我們傳入一個lambda表示式進行處理,非常方便。
總結
- 1、如果只是單純想處理程式碼邏輯中可能出現的null異常,那麼其實我覺得使用IDE結合註解的方式可能會更加方便一點,當然使用
Optional
也是可以的 - 2、如果我們想提供一個對外的API,我認為將API的成員屬性、方法返回值宣告為
Optional
可能會更好一點,因為別人一看就知道,該API方法簽名可能會返回空值,使用者只需要用一個Optional
對接收即可! - 3、要想減少空異常,關鍵還得提升自己的編碼能力!身正不怕影子斜。