使用Optional優雅處理null


  先假設一個場景。如下所示

 1 public class Person {
 2 
 3     private String name;
 4 
 5     public Person() {
 6     }
 7 
 8     public Person(String name) {
 9         this.name = name;
10     }
11 
12     public String getName() {
13         return name;
14     }
15 }

  我們有一個Person類,有一個屬性是name。有如下代碼:

1 public static void main(String[] args) {
2     Person person = new Person();
3 
4     String name = person.getName();
5 
6     if (name.equals("Jackson")) {
7         System.out.println("My name is Jackson!");
8     }
9 }

  我們判斷獲取person的name,然后判斷person的name是不是Jackson。因為person的name為null,所以name.equals("Jackson")這段代碼會報空指針的異常。

  我們有多種方式來處理空指針的異常,一種是我們考察我們的業務邏輯,當需要返回一個null值時返回一個有意義的NullObject。例如空字符串對應返回字符串的情況,空列表對應返回list的情況,對一些特殊的對象,可以根據不同的業務邏輯創建一些Null對象。參考《Effictive Java》第43條,《重構》9.7節。

  對於我們的例子,當name為null時,getName方法返回一個""字符串。當接下來取出name來進行操作時就不會出現空指針的異常。

1 public String getName() {
2     if (name == null) {
3         return "";
4     } else {
5         return name;
6     }
7 }

  另一種是在調用的時候判斷是否為空,對於我們的例子,如下代碼:

1 if (name != null && name.equals("Jackson")){}

  通過判斷name是否為空,若非空再判斷name是否等於Jackson。通過這樣的方式可以解決空指針異常的問題。

  但是兩種方案都有一定的缺點,對於第一種方案,String和集合類型的Null對象很好確認,就是空字符串和空集合。但是對於一些特殊的對象,創建Null對象需要更多的步驟,更多的設計。總之就是兩個字,麻煩。

  對於第二種方案,這個也是我們最常用的。但是這個方案有一個問題,就是經常會忘記判空。對於一個方法other.method(a, b),我們常常不會忘記對a和b進行判空,而對方法的返回值卻經常忘記判空。而這個空指針異常是在運行時才會被發現,如果空指針的情況十分的罕見,那么很可能很長一段時間都不會發現這個異常。我常常碰到的一種情況是當數據庫中存在臟數據的時候,正常的數據是不應該存在null的,但是即使是生產環境也很有可能混入一兩個臟數據,很可能這罕見的臟數據導致程序報錯。可能這個時候再去修復bug,代價比開發階段高很多。

  為了優雅地處理null的情況,可以使用Java8的新特性Optional。API不說了,直接上代碼

 1 public class Person {
 2 
 3     private String name;
 4 
 5     public Person() {
 6     }
 7 
 8     public Person(String name) {
 9         this.name = name;
10     }
11 
12     public Optional<String> getName() {
13         return Optional.ofNullable(name);
14     }
15 
16     public static void main(String[] args) {
17         Person person = new Person();
18 
19         Optional<String> optionalName = person.getName();
20         if (optionalName.isPresent()) {
21             String name = optionalName.get();
22             System.out.println("My name is :" + name);
23         } else {
24             System.out.println("Who am I?");
25         }
26     }
27 }

  在getName里,我們由原來直接返回name,改成返回Optional<String>。通過Optional.ofNullable(T)靜態方法,可以創建一個Optional對象。如果傳入的對象是null,那么isPresent返回false,否則返回true。在上訴代碼中,Person的name沒有設置,optionalName.isPresent()返回的是false,所以打印出的應該是Who am I?

  從代碼上看,這個和第二種方案,對對象判空的方法沒有區別,都是先判斷是否存在,然后再對對象進行操作。因為我們沒法直接獲取所需的對象,而是獲得Optional對象,需要從Optional中獲取我們需要的對象,因為不判空取不到所需對象,所以我們就不會忘了判空這步操作了。


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM