[英]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年有Optional
, Map.get
可能會返回一個Optional
。)
我不知道你在哪里聽到的建議是,Optional比例外更可取,但是誰告訴你這是不明智的。 如果你之前拋出異常,你可能仍然會拋出異常; 如果之前返回null,則可以考慮返回Optional
。
在可能出現錯誤的情況下,合適的數據類型為Try。
Try不使用抽象'present'或'empty',而是使用抽象'失敗'或'成功'。
由於Java 8不提供Try,因此有必要使用一些3.方庫。 (也許我們會在Java 9中看到它添加?)
聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.