异常

异常类

Kotlin 中所有异常类继承自 Throwable 类。 每个异常都有消息、堆栈回溯信息以及可选的原因。

使用 throw 表达式来抛出异常:

  1. fun main() {
  2. //sampleStart
  3. throw Exception("Hi There!")
  4. //sampleEnd
  5. }

使用 try……catch 表达式来捕获异常:

  1. try {
  2. // 一些代码
  3. } catch (e: SomeException) {
  4. // 处理程序
  5. } finally {
  6. // 可选的 finally 块
  7. }

可以有零到多个 catch 块,finally 块可以省略。 但是 catchfinally 块至少需有一个。

Try 是一个表达式

try 是一个表达式,意味着它可以有一个返回值:

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

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

受检异常

Kotlin 没有受检异常。这其中有很多原因,但我们会提供一个简单的示例 that illustrates why it is the case。

以下是 JDK 中 StringBuilder 类实现的一个示例接口:

  1. Appendable append(CharSequence csq) throws IOException;

这个签名是说,每次我追加一个字符串到一些东西(一个 StringBuilder、某种日志、一个控制台等)上时,我就必须捕获 IOException。 为什么?因为相应实现可能正在执行 IO 操作(Writer 也实现了 Appendable)。 其结果是这种代码随处可见:

  1. try {
  2. log.append(message)
  3. } catch (IOException e) {
  4. // 必须要安全
  5. }

这并不好,看看《Effective Java》第三版 第 77 条:不要忽略异常 就知道了。

Bruce Eckel says this about checked exceptions:

通过一些小程序测试得出的结论是异常规范会同时提高开发者的生产力与代码质量,但是大型软件项目的经验表明一个不同的结论——生产力降低、代码质量很少或没有提高。

And here are some additional thoughts on the matter:

If you want to alert callers about possible exceptions when calling Kotlin code from Java, Swift, or Objective-C, you can use the @Throws annotation. Read more about using this annotation for Java and for Swift and Objective-C.

Nothing 类型

在 Kotlin 中 throw 是表达式,所以你可以使用它(比如)作为 Elvis 表达式的一部分:

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

throw 表达式的类型是 Nothing 类型。 这个类型没有值,而是用于标记永远不能达到的代码位置。 在你自己的代码中,你可以使用 Nothing 来标记一个永远不会返回的函数:

  1. fun fail(message: String): Nothing {
  2. throw IllegalArgumentException(message)
  3. }

当你调用该函数时,编译器会知道在该调用后就不再继续执行了:

  1. val s = person.name ?: fail("Name required")
  2. println(s) // 在此已知“s”已初始化

当处理类型推断时还可能会遇到这个类型。这个类型的可空变体 Nothing? 有一个可能的值是 null。如果用 null 来初始化一个要推断类型的值,而又没有其他信息可用于确定更具体的类型时,编译器会推断出 Nothing? 类型:

  1. val x = null // “x”具有类型 `Nothing?`
  2. val l = listOf(null) // “l”具有类型 `List<Nothing?>

Java 互操作性

与 Java 互操作性相关的信息,请参见 Java 互操作性章节中的异常部分。