簡體   English   中英

可選vs拋出異常

[英]Optional vs throwing an exception

是不是因為Java 1.8返回Optional對象比拋出異常更可取? 我越來越多地看到這樣的代碼:

  public Optional<?> get(int i) {
        // do somtething
        Object result = ...
        Optional.ofNullable(result);
    }

而不是這個:

public Object get(int i) {
        if(i<0 || i>=size) {
            throw new IndexOutOfBoundsException("Index: " + i + ". Size: " + size);
        }
        // do somtething
        Object result = ...
        return result;
    }

是否意味着我們需要忘記舊方法並使用新方法? 什么是Optional的適合?

您提供的示例不是 Optional的適當用法。 空Optional表示由於調用者無法預測的原因而缺少的值。 它是法律調用方法的結果。

您作為“舊習慣用法”呈現的代碼會執行輸入驗證,如果輸入無效,則會拋出未經檢查的異常。 即使您引入Optional,此行為也應保持不變。 唯一的區別是Object get(i)的返回值可能為null,而Optional<?> get(i)的返回值永遠不為null,因為Optional實例的特殊狀態表示缺少值。

返回Optional而不是可空值的方法的優點是消除了樣板代碼,該代碼必須在嘗試對返回值執行任何操作之前進行例行的空檢查。 純粹在方法中使用Optional有許多其他優點。 例如:

static Optional<Type> componentType(Type type) {
  return Optional.of(type)
                 .filter(t -> t instanceof ParameterizedType)
                 .map(t -> (ParameterizedType) t)
                 .filter(t -> t.getActualTypeArguments().length == 1)
                 .filter(t -> Optional.of(t.getRawType())
                                      .filter(rt -> rt instanceof Class)
                                      .map(rt -> (Class<?>) rt)
                                      .filter(Stream.class::isAssignableFrom)
                                      .isPresent())
                 .map(t -> t.getActualTypeArguments()[0]);

這里的一個重要的好處是完美范圍控制:同名t ,在每個新的范圍為適當的處理的該階段的類型的可變重復使用。 因此,不是在其使用壽命到期后被迫在范圍內使用變量,而是為每個后續變量創建一個新名稱,使用這個習慣用法,我們有了我們需要進行的精確最小值。

只是為了感興趣,你可以完全按照Optional來實現equals

@Override public boolean equals(Object obj) {
  return Optional.ofNullable(obj)
                 .filter(that -> that instanceof Test)
                 .map(that -> (Test)that)
                 .filter(that -> Objects.equals(this.s1, that.s1))
                 .filter(that -> Objects.equals(this.s2, that.s2))
                 .isPresent();
}

雖然我發現這個成語非常干凈和可讀,但它目前還沒有足夠優化,不適合作為一個有價值的選擇。 但是,Java的未來版本可能會使這一點變得可行。

可以平等地濫用異常,空值和可選項。 在這種特殊情況下,我認為你可能會濫用可選項,因為你默默地隱藏了一個前提條件違規並將其轉換為正常返回。 在收到代碼中的空選項后,調用者無法區分“我正在尋找的東西不在那里”和“我問了一個無效的問題。”

因為Optional是新的,所以也有過度使用的傾向; 希望隨着時間的推移,正確的模式將被內化。

可選是null對象模式的示例; 當“沒有任何東西”是合理的預期結果時,它提供了一種安全的方式來說“沒有任何東西”。 (返回空數組或空集合在這些域中是類似的例子。)無論你是想用null / optional表示“什么都沒有”vs一個異常通常是“沒有任何東西”是否是一個普遍預期的情況,或者是否特殊。 例如,如果映射不存在,沒有人希望Map.get拋出異常; 映射不存在是預期的,而不是例外的結果。 (如果我們在1997年有OptionalMap.get可能會返回一個Optional 。)

我不知道你在哪里聽到的建議是,Optional比例外更可取,但是誰告訴你這是不明智的。 如果你之前拋出異常,你可能仍然會拋出異常; 如果之前返回null,則可以考慮返回Optional

在可能出現錯誤的情況下,合適的數據類型為Try。

Try不使用抽象'present'或'empty',而是使用抽象'失敗'或'成功'。

由於Java 8不提供Try,因此有必要使用一些3.方庫。 (也許我們會在Java 9中看到它添加?)

試試Java

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM