Kotlin Reference: Exceptions

Exception Classes

  在 Kotlin 中,所有的异常类都是 Throwable 的子类。每一个异常都有一个消息、调用栈和一个可选的原因。

  使用 throw 表达式抛出异常对象:

throw MyException("Hi There!")

  使用 try 表达式捕获异常:

try {
// some code
}
catch (e: SomeException) {
// handler
}
finally {
// optional finally block
}

  可以有零个或多个 catch 代码块,finally 块可以省略,但必须至少有一个 catchfinally

Try is an expression

  try 是一个表达式,也就是说,它可以有返回值。

val a: Int? = try { parseInt(input) } catch (e: NumberFormatException) { null }

  try 表达式的返回值是 try 块中的最后一个表达式,或者是 catch 块中的最后一个表达式。finally 块中的内容不会影响表达式的结果。

Checked Exceptions

  Kotlin 中没有受检异常(Checked Exception),这样做有很多原因,我们会提供一个简单的例子。

  下面是 JDK 中的一个接口,由 StringBuilder 类实现:

Appendable append(CharSequence csq) throws IOException;

该接口的签名表示,每当追加一个字符串到某处(如 StringBuilder,某种日志,控制台等),就必须捕获 IOExceptions,因为可能在进行 IO 操作(Writer 也实现了 Appendable)······因此,下面的代码随处可见:

try {
log.append(message)
}
catch (IOException e) {
// Must be safe
}

  正如 Effective Java “条目 64:不要忽视异常” 所述,这样并不好。

Bruce Eckel 在 Does Java need Checked Exceptions? 中说:

通过对小型程序的审查可以得出这样的结论:规范的异常可以提高开发者的效率,并提高代码质量。但凭借大型软件项目的开发经验则会得出不同的结论:这样做会降低效率,对代码质量的提升也微乎其微。

  其他的例证还有:

The Nothing type

  throw 在 Kotlin 中也是一个表达式,可以把它作为 Elvis 表达式的一部分:

val s = person.name ?: throw IllegalArgumentException("Name required")

  throw 表达式的类型是一个特殊的类型 Nothing,这个类型没有值,用于标记不可能执行到的代码位置。在代码中,可以使用 Nothing 标记从不返回的函数:

fun fail(message: String): Nothing {
throw IllegalArgumentException(message)
}

当你调用这个函数时,编译器知道程序不会继续往下执行。

val s = person.name ?: fail("Name required")
println(s) // s is known to be initialized at this point

【注】上面的代码中,println(s) 时可以确定 s 已经被初始化,因为如果 person.namenullfail("Name required") 会抛出异常,程序不会再往下执行。

Java Interoperability

  对于与 Java 的互操作性的信息,请参考 Java Interoperability 中关于异常的一节。