Kotlin使用心得(二):Any與Nothing間的奇妙關係、以及與Java中Void的愛恨情仇

Carter Chen
5 min readMay 26, 2018

--

Photo by Patrick McManaman on Unsplash

寫在前面

首先,我覺得標題很聳動,如果你是因為這樣被騙進來,然後覺得文章寫得並不怎麼樣,請不要討厭我。

內容其實並沒有什麼特別的,只是因為我發現了Any這個看起來很厲害的類別,深入探討後發現的一些東西。本篇也大量的引用了Kotlin has Nothing but there is nothing like Nothing in Java這篇文章的內容。

本文開始!

Any與Nothing

Any類似Java中的ObjectObject是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等數值,然後又需要在後續進行檢查變數數值的這種強型別帶來的「副作用」,至於是否在其它地方也有它可以發揮的機會呢?讓我們繼續看下去~

--

--