Kotlin使用心得(二):Any與Nothing間的奇妙關係、以及與Java中Void的愛恨情仇
寫在前面
首先,我覺得標題很聳動,如果你是因為這樣被騙進來,然後覺得文章寫得並不怎麼樣,請不要討厭我。
內容其實並沒有什麼特別的,只是因為我發現了Any
這個看起來很厲害的類別,深入探討後發現的一些東西。本篇也大量的引用了Kotlin has Nothing but there is nothing like Nothing in Java這篇文章的內容。
本文開始!
Any與Nothing
Any
類似Java中的Object
,Object
是Java中所有類別的父類別,而Any
便是Kotlin中所有類別的父類別。雖然在compiler中看不到,實際上是偷偷摸摸的自己裝好了。
引述文章翻译:Kotlin 中的 Nothing 和 Unit中的內容:
Kotlin 里所有东西都有类型:对象、函数…… 同样,“没有东西”也有类型:Nothing。
如果一個函數,其返回的數值類型是Nothing
的話,這代表什麼意思呢?這代表的是:
這是一個不可能執行成功的函數。
Nothing(Kotlin)與void(Java)愛恨情仇
首部曲:Unreachable code
以拋出錯誤的函數為例,Java中的reportError()
:
void reportError() {
throw new RuntimeException();
}
Kotlin中的reportError()
:
fun reportError(): Nothing {
throw RuntimeException()
}
再來看一下相同邏輯的程式碼,在編譯器上會有什麼樣的表現:
Java:
int i = 0;void exampleOne() { reportError(); // 拋出錯誤
i = 1; // 這行是無法執行的,但編譯器不會提出警告}
Kotlin:
var i = 0;fun exampleOne() {reportError(); // 拋出錯誤
i = 1; // 編譯器會提示'Unreachable code'的警告
}
二部曲:貓王、三元運算符(… ? … : …)
Java:
void exampleTwo(Map<String, String> map) {
String data = map.containsKey("key") ? map.get("key") : reportError(); // 編譯失敗:'Incompatible types' error.}
這邊可以看到,Java中的reportError()
函數返回的是void
類型的數值,但data
要求的是String
類型的數值,所以在Java中會出現「類型不相容」的錯誤。
Kotlin:
fun exampleTwo(map: Map<String, String>) {
val data: String = map["key"] ?: reportError() // 編譯成功}
由於Kotlin中reportError()
函數返回的是Nothing
類型的數值,而Nothing
即為所有類型的子類別,所以儘管data
要求的是String
類別,依然可以通過編譯。
三部曲:函數回傳類型
Java:
String exampleThree(int n) { if (n > 5) {
return "Ok";
} reportError(); // 編譯失敗:'Missing return statement' error.}
Java中的reportError()
函數返回的是void
類型的數值,但exampleThree()
函數要求的是String
類型的返回數值,此函數中除了符合條件的狀態下會返回“Ok”字串以外,在不符合條件的狀況下沒有使用return返回數值,所以會出現「沒有返回數值聲明」的錯誤,儘管程式執行到這邊就一定會發生錯誤,不可能返回任何數值。
Kotlin:
fun exampleThree(n: Int): String { if (n > 5) {
return "Ok";
} reportError(); // throws RuntimeException}
在Kotlin的話,編譯器知道reportError()
返回的會是Nothing類型的數值,因此理解既然這段程式碼不可能執行成功,那也就不可能會有返回數值的狀況了,因此可以通過編譯。
結論
Nothing
在上述例子中的使用情境,確實克服了在Java中,當明確需要一個型別的返回數值時,因為傳遞的參數不合理,而必須要返回null、-1等數值,然後又需要在後續進行檢查變數數值的這種強型別帶來的「副作用」,至於是否在其它地方也有它可以發揮的機會呢?讓我們繼續看下去~