Kotlin 中所有異常類(lèi)都是 Throwable 類(lèi)的子孫類(lèi)。
每個(gè)異常都有消息、堆?;厮菪畔⒑涂蛇x的原因。
使用 throw{: .keyword }-表達(dá)式來(lái)拋出異常。
throw MyException("Hi There!")
使用 try{: .keyword }-表達(dá)式來(lái)捕獲異常。
try {
// 一些代碼
}
catch (e: SomeException) {
// 處理程序
}
finally {
// 可選的 finally 塊
}
可以有零到多個(gè) catch{: .keyword } 塊。finally{: .keyword } 塊可以省略。
但是 catch{: .keyword } 和 finally{: .keyword } 塊至少應(yīng)該存在一個(gè)。
try{: .keyword } 是一個(gè)表達(dá)式,即它可以有一個(gè)返回值。
val a: Int? = try { parseInt(input) } catch (e: NumberFormatException) { null }
try{: .keyword }-表達(dá)式的返回值是 try{: .keyword } 塊中的
最后一個(gè)表達(dá)式或者是(所有)catch{: .keyword } 塊中的最后一個(gè)表達(dá)式。
finally{: .keyword } 塊中的內(nèi)容不會(huì)影響表達(dá)式的結(jié)果。
Kotlin 沒(méi)有受檢的異常。這其中有很多原因,但我們會(huì)提供一個(gè)簡(jiǎn)單的例子。
以下是 JDK 中 StringBuilder 類(lèi)實(shí)現(xiàn)的一個(gè)示例接口
Appendable append(CharSequence csq) throws IOException;
這個(gè)簽名是什么意思? 它是說(shuō),每次我追加一個(gè)字符串到一些東西(一個(gè) StringBuilder、某種日志、一個(gè)控制臺(tái)等)上時(shí)
我就必須捕獲那些 IOException。 為什么?因?yàn)樗赡苷趫?zhí)行 IO 操作(Writer 也實(shí)現(xiàn)了 Appendable)……
所以它導(dǎo)致這種代碼隨處可見(jiàn)的出現(xiàn):
try {
log.append(message)
}
catch (IOException e) {
// 必須要安全
}
這并不好,參見(jiàn)《Effective Java》 第 65 條:不要忽略異常。
Bruce Eckel 在《Java 是否需要受檢的異常?》(Does Java need Checked Exceptions?) 中指出:
通過(guò)一些小程序測(cè)試得出的結(jié)論是異常規(guī)范會(huì)同時(shí)提高開(kāi)發(fā)者的生產(chǎn)力和代碼質(zhì)量,但是大型軟件項(xiàng)目的經(jīng)驗(yàn)表明一個(gè)不同的結(jié)論——生產(chǎn)力降低、代碼質(zhì)量很少或沒(méi)有提高。
其他相關(guān)引證:
在 Kotlin 中 throw 是表達(dá)式,所以你可以使用它(比如)作為 Elvis 表達(dá)式的一部分:
val s = person.name ?: throw IllegalArgumentException("Name required")
throw 表達(dá)式的類(lèi)型是特殊類(lèi)型 Nothing。
該類(lèi)型沒(méi)有值,而是用于標(biāo)記永遠(yuǎn)不能達(dá)到的代碼位置。
在你自己的代碼中,你可以使用 Nothing 來(lái)標(biāo)記一個(gè)永遠(yuǎn)不會(huì)返回的函數(shù):
fun fail(message: String): Nothing {
throw IllegalArgumentException(message)
}
當(dāng)你調(diào)用該函數(shù)時(shí),編譯器會(huì)知道執(zhí)行不會(huì)超出該調(diào)用:
val s = person.name ?: fail("Name required")
println(s) // 在此已知“s”已初始化
與 Java 互操作性相關(guān)的信息,請(qǐng)參見(jiàn) Java 互操作性章節(jié)中的異常部分。