2015年8月2日 星期日

[名詞定義] Optional

null的最根本問題在於語意含糊不清,雖然就字面來說,

null可以是「不存在」、「沒有」、「無」或「空A」的概念,

因此在應用時,總是令人感到模稜兩可,也就讓開發者有了各自解釋的空間,

當開發者想到這邊可以沒有東西,就直接放個null,好像沒什麼可以回傳的,

就丫廿沙力的傳回個null,然後呼叫者就總是忘了檢查null,引發各種可能的錯誤。



由於null的根本問題在於含糊不明確,要避免使用null的方式,

就是確認過去使用null的時機與目的,並使用明確的語義。

在過去使用null的情況中,開發者於方法中傳回null,

通常代表著客戶端必須檢查是否為null,

並在null的情況下使用預設值,以便後續程式繼續執行。

舉個例子來

  public static void main(String[] args) {  
     String nick = getNickName("tom");  
     if (nick == null) {  
       nick = "friend";  
     }  
     System.out.println(nick);  
   }  
   private static String getNickName(String name) {  
     Hashtable<String, String> ht = new Hashtable<String, String>();  
     ht.put("John", "JJ");  
     ht.put("mark", "mms");  
     ht.put("bert", "bird");  
     ht.put("summer", "sun");  
     if (ht.containsKey(name)) {  
       return ht.get(name);  
     }  
     return null;  
   }  

以上程式中,如果呼叫getNickName()忘記檢查null,

那麼就會直接顯示null,但是如果是複雜一點的程式,

只要流程中出現一個null,輕則結果錯誤,重則crash。


解決方式是getNickName()修改使一定會傳回Optional<String>實例,

但絕不要傳回null。Optional的語義是它可能包含也可能不包括值

要建立Optional實例有幾個靜態方式,使用of()方法可

以指定非null值建立Optional實例,使用empty()方法可以建立不包裏值

的Optional實例。使用Optional來改寫上頭的getNickName()方法:

  public static void main(String[] args) {  
     String nick=getNickName("tom").get();  
     System.out.println(nick);  
   }  
   private static Optional<String> getNickName(String name) {  
     Hashtable<String, String> ht = new Hashtable<String, String>();  
     ht.put("John", "JJ");  
     ht.put("mark", "mms");  
     ht.put("bert", "bird");  
     ht.put("summer", "sun");  
     String nickName=null;  
     if (ht.containsKey(name)) {  
       nickName= ht.get(name);  
     }  
     return nickName==null?Optional.empty():Optional.of(nickName);  
   }  

此時如果Optional並沒有值,會抛出NoSuchElementException

Exception in thread "main" java.util.NoSuchElementException: No value present
at java.util.Optional.get(Optional.java:135)
at javaapplication37.JavaApplication37.main(JavaApplication37.java:14)
Java Result: 1

這實現了一個觀念「速錯」,讓錯誤很明顯的被發現中,得以即時修改程式。

我們把main的程式碼改成如下

  public static void main(String[] args) {  
     Optional<String> optional=getNickName("tom");  
     String nick="friend";  
     if (optional.isPresent())  
     {  
       nick=optional.get();  
     }  
     System.out.println(nick);  
   }  

讓程式先去檢查回傳回來的Optional是否有包含值,但這樣比較麻煩,還有一招

使用orElse,只要沒有值,就會輸出指定的字串。

  public static void main(String[] args) {  
     Optional<String> optional=getNickName("tom");  
     System.out.println(optional.orElse("friend"));  
   }  
資料來源:

http://openhome.cc/Gossip/Java/Optional.html

沒有留言:

張貼留言