sealed 介面
June 14, 2022在〈sealed 類別〉談過 sealed
,sealed
也可以用來修飾介面,這表示你很清楚介面會有幾種實作品或子介面,不允許其他人實作該介面或增加直接的子介面。
Either 對/錯
sealed
介面的實作類別必須在同一套件中定義,並且必須使用 final
、non-sealed
、或 sealed
修飾,子介面必須在同一套件中定義,並且必須使用 non-sealed
、或 sealed
修飾。
舉例來說,有些語言允許函式傳回兩個值,有些開發者會用來傳回錯誤值與正確值,遇到這類函式,函式的呼叫者必須檢查傳回值,分別針對函式執行成功及失敗進行處理。
如果想在 Java 模擬這種效果,可以設計 Either
介面,因為只有錯誤與正確的可能性,可以使用 sealded
修飾 Either
介面,只允許有 Left
、Right
兩個實作類別:
如果想在 Java 模擬這種效果,可以設計 Either
介面,因為只有錯誤與正確的可能性,可以使用 sealded
修飾 Either
介面,只允許有 Left
、Right
兩個實作類別:
package cc.openhome;
public sealed interface Either permits Left, Right {
default Object left() {
throw new IllegalStateException("nothing left");
}
default Object right() {
throw new IllegalStateException("nothing right");
}
}
因為錯誤值與正確值可能是各種型態,這邊使用泛型來參數化,代表錯誤值 Left
必須重新定義 left
方法:
package cc.openhome;
public record Left(Object value) implements Either {
@Override
public Object left() {
return value;
}
}
因此若是 Left
實例,呼叫 left
就不會拋出例外,record
類別是 final
類別,也就不用加上 final
修飾了;類似地,代表正確值 Right
必須重新定義 right
方法:
package cc.openhome;
public record Right(Object value) implements Either {
@Override
public Object right() {
return value;
}
}
這麼一來,若是 Right
實例,呼叫 right
就不會拋出例外。
模式比對
現在可以使用 Either
來作為函式的傳回值。例如:
package cc.openhome;
public class EitherDemo {
static Either div(Integer a, Integer b) {
if(b == 0) {
return new Left("除零錯誤 %d / %d".formatted(a, b));
}
return new Right(a / b);
}
public static void main(String[] args) {
Integer a = Integer.parseInt("10");
Integer b = Integer.parseInt("0");
Either either = div(a, b);
// 檢查傳回結果
if(either instanceof Left) { // 如果有錯誤
System.err.println(either.left());
}
else if(either instanceof Right) { // 若是正確值
System.out.printf("%d / %d = %d%n", a, b, either.right());
}
}
}
由於使用了 sealed
修飾了 Either
,而且使用 record
類別實作 Left
與 Right
,其他人若要處理傳回值,就必須使用 instanceof
來比對型態,才知道是錯誤或正確結果,這邊使用 instanceof
並無不妥。
Either
的概念來自函數式設計,這邊的 instanceof
,相當於模式比對(Pattern matching),未來 Java 在模式比對語法還會有進一步的加強,使用起來就很方便了;另外Left、Right總是會讓我想到一則笑話「Your left brain has nothing right, and your right brain has nothing left!」。
你可能會覺得 Either
跟 Optional
有點像,Optional
是「無」或「有」的概念,Either
是「錯」或「對」的概念。
另外,Either
透過 left
或 right
時,因為現在都是以 Object
傳回,你必須知道實例的型態,才可以正確地 cast;Java 支援泛型(generics),可以運用泛型來定義 Either
可以有的 left
、right
型態,並請編譯器協助檢查型態的正確性,這在之後會再談到。