2014-11-23 51 views
2

https://code.google.com/p/guava-libraries/wiki/UsingAndAvoidingNullExplained的解釋是番石榴(和後來的java 8)添加了一個通用類可選,以清除空檢查。爲什麼guava/java使用possible.isPresent()而不是Optional.isPresent(可能)?

如果一個函數返回一個Optional,它需要調用者在使用它之前解開字符串。

這種形式

Optional<String> possible = returnAnAbsentOptional(); 
if(possible.isPresent()){ 
    System.out.println(possible.get()) 
} 

會正常完成。如果returnAnAbsentOptional返回null,我們有一個NPE一遍。

我的問題是,爲什麼Guava/Java使用possible.isPresent()而不是Optional.isPresent(可能),它可以相應地響應null值?

+5

我不明白這個問題。如果你通過'null'' Optional',那麼你就有一些嚴重的問題。 – 2014-11-23 12:44:38

回答

3

因爲對空值作出反應的正確方法是拋出一個NullPointerException,這就是您在possible == null時調用possible.isPresent()時得到的結果。

Java作爲一種語言允許任何參考類型的值爲null。 Java的用戶不需要null值時,他們不需要他們,並正確處理他們當他們需要他們。當他們失敗時,可能會拋出NullPointerException

Optional不是寫作== null的替代方案。 Optional是使用null來替代。如果您選擇不使用null,然後使用null,您創建了一個錯誤。

對程序員引入的錯誤作出反應的正確方法是什麼?讓我們嘗試在一個例子你的想法Optional.isPresent(value)

public abstract class BaseClass { 
    static boolean optionalIsPresent(Optional<?> possible) { 
    return (possible == null) ? false : possible.isPresent(); 
    // return possible.isPresent(); 
    } 

    public final String name; 

    public Optional<Integer> getID(); 

    protected BaseClass() { 
    if (optionalIsPresent(getID())) { 
     name = "number " + getID().get(); 
    } else { 
     name = "nameless"; 
    } 
    } 
} 

public class DerivedClass extends BaseClass { 
    private final int id; 

    public DerivedClass(int id) { 
    this.id = id; 
    } 

    public Optional<Integer> getID() { 
    return Optional.of(id); 
    } 
} 

有一個程序員的錯誤在這裏,他們正試圖將它設置之前使用最終場。

如果optionalIsPresent(null)回報false,那麼上面的代碼沒有錯誤執行,並且我們有一個對象與行爲從什麼我們認爲我們指定的不同:getID()存在,但name"nameless"。我們得到的結果與我們從未使用Optional的結果相同,並且僅對「缺席」和「現在」使用了空值和非空值。

但是,通過僅使用absent()來表示absent(),我們不正確的代碼會拋出NullPointerException

6

可選的想法不是爲了防止所有的NPE。我們的想法是明確指出一個API方法可以返回缺少的值,並強制調用者意識到並處理它。

當然,如果此方法返回null而不是Optional,那麼您仍然會得到一個NPE,但這是一個巨大的設計問題。返回一個Optional的方法應該返回一個Optional(存在或不存在),而不是null。

而在OO語言中,使用此對象的方法而不是靜態方法訪問對象的狀態會更自然。

+0

我並不是問代碼是否有大量的設計問題,我正在問具體爲什麼他們會選擇他們所做的。 – 2014-11-23 12:51:47

+2

因爲在OO語言中,使用此對象的方法而不是靜態方法訪問對象的狀態會更自然。 – 2014-11-23 12:54:06

+0

@JBNizet我會將該評論添加到答案中 - 這與所提問題有關。 – 2014-11-23 13:03:35

0

面嚮對象語言的基本設計標準是封裝,它表示對象的內部狀態應該只對對象本身可見。因此,通常認爲通過對象的方法而不是通過靜態方法來訪問對象的狀態是「更清潔」的面向對象設計。在Java中,這可能是一個有趣的問題,因爲靜態方法也屬於一個類,但仍然更加自然。

3

JB Nizet給出了一個很好的答案,但我將從面向契約的編程的未來展開。這也被稱爲按合同設計。

可選< T>,作出關於被叫方的方法可能返回null合同可以是

  1. 在該方法的javadoc註釋中描述的唯一方法之前「這可能返回null如果XYZ」
  2. 把它在一個設計文檔,沒有人會讀
  3. 創建自己的可選類

帶有可選< T>,你是減少NullPointerExceptions的頻率。如果您在包裹合同中提供了「我將使用可選的合同」合同:

  • 如果您返回一個字符串,則您的調用者不需要執行檢查。 (如果調用者爲NPE崩潰,那麼崩潰不是他們的錯,這會成爲違反合同的錯,這也是爲什麼一個可選的方法不能返回null,它違背合約只返回非 - 空對象)
  • 如果您返回可選<字符串>,您的呼叫者不能忘記執行可選檢查。

最後一點是爲什麼它是Optional.isPresent()而不是Optional.isPresent(Object)。 他們可能會忘記調用後面,如果有可能你的方法返回null。 他們不能忘記打電話給前者。

相關問題