ZetCode

Kotlin throw 关键字

最后修改于 2025 年 4 月 19 日

Kotlin 的异常处理系统允许使用 throw 关键字显式抛出异常。本教程将通过实际示例深入探讨 throw 关键字。

基本定义

Kotlin 中的 throw 关键字用于显式抛出异常。当抛出异常时,程序的正常流程会被中断。异常会沿调用栈向上冒泡,直到被 try-catch 块捕获。

抛出内置异常

throw 最简单的用法是抛出标准的 Kotlin 异常。此示例演示了抛出 IllegalArgumentException

ThrowBuiltIn.kt
package com.zetcode

fun checkAge(age: Int) {
    if (age < 0) {
        throw IllegalArgumentException("Age cannot be negative")
    }
    println("Age is valid: $age")
}

fun main() {
    try {
        checkAge(-5)
    } catch (e: IllegalArgumentException) {
        println(e.message) // Output: Age cannot be negative
    }
}

在这里,当年龄参数为负数时,我们抛出一个 IllegalArgumentException。异常在 main 函数中被捕获,并打印其消息。这展示了基本的异常抛出和处理。

创建自定义异常

Kotlin 允许通过扩展 Exception 类来创建自定义异常类。此示例展示了如何定义和抛出自定义异常。

CustomException.kt
package com.zetcode

class InvalidEmailException(message: String) : Exception(message)

fun validateEmail(email: String) {
    if (!email.contains("@")) {
        throw InvalidEmailException("Invalid email format")
    }
    println("Email is valid: $email")
}

fun main() {
    try {
        validateEmail("user.example.com")
    } catch (e: InvalidEmailException) {
        println(e.message) // Output: Invalid email format
    }
}

我们定义了一个自定义的 InvalidEmailException 类,它扩展了 Exception。当电子邮件不包含“@”时,validateEmail 函数会抛出此异常。自定义异常使错误处理更具体。

在表达式中抛出异常

Kotlin 允许将 throw 用作表达式。这使得可以在需要表达式的地方抛出异常,例如在 Elvis 运算符中。

ThrowExpression.kt
package com.zetcode

fun getLength(str: String?): Int {
    return str?.length ?: throw IllegalArgumentException("String cannot be null")
}

fun main() {
    try {
        println(getLength(null))
    } catch (e: IllegalArgumentException) {
        println(e.message) // Output: String cannot be null
    }
}

这里,throw 被用作 Elvis 运算符表达式的一部分。如果字符串为 null,则抛出异常。这种模式在 Kotlin 中进行空值检查很常见。

重新抛出异常

有时您需要捕获一个异常,执行一些操作,然后重新抛出它。此示例展示了如何在 Kotlin 中重新抛出异常。

RethrowException.kt
package com.zetcode

fun processNumber(str: String) {
    try {
        val num = str.toInt()
        println("Processed number: $num")
    } catch (e: NumberFormatException) {
        println("Logging error: ${e.message}")
        throw e // Rethrow the exception
    }
}

fun main() {
    try {
        processNumber("abc")
    } catch (e: NumberFormatException) {
        println("Caught rethrown exception") // Output: Caught rethrown exception
    }
}

processNumber 函数捕获一个 NumberFormatException,记录它,然后重新抛出它。main 函数捕获重新抛出的异常。这种模式在传播异常之前进行日志记录时很有用。

从 Lambda 抛出异常

Kotlin 中的 Lambda 表达式可以像常规函数一样抛出异常。此示例展示了在 lambda 表达式中抛出异常。

LambdaException.kt
package com.zetcode

fun calculate(operation: (Int, Int) -> Int, a: Int, b: Int): Int {
    return try {
        operation(a, b)
    } catch (e: ArithmeticException) {
        println("Calculation error: ${e.message}")
        -1
    }
}

fun main() {
    val result = calculate({ x, y ->
        if (y == 0) throw ArithmeticException("Division by zero")
        x / y
    }, 10, 0)
    
    println(result) // Output: -1
}

传递给 calculate 的 lambda 在尝试除以零时抛出一个 ArithmeticException。异常在 calculate 函数中被捕获。这显示了异常如何从 lambda 传播。

将 throw 与 Nothing 类型一起使用

在 Kotlin 中,throw 具有特殊的类型 Nothing。这意味着它可以在需要任何类型的地方使用。编译器知道在 throw 之后不会继续执行。

NothingType.kt
package com.zetcode

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

fun getUser(id: Int): String {
    return if (id > 0) {
        "User$id"
    } else {
        fail("Invalid user ID")
    }
}

fun main() {
    try {
        println(getUser(1)) // Output: User1
        println(getUser(-1)) // Throws exception
    } catch (e: IllegalArgumentException) {
        println(e.message) // Output: Invalid user ID
    }
}

fail 函数返回 Nothing,允许它在 getUser 中需要 String 的地方使用。编译器知道 else 分支将抛出异常,并且不会正常返回。

异常处理最佳实践

来源

Kotlin 异常文档

本教程深入探讨了 Kotlin 的 throw 关键字,展示了如何抛出内置和自定义异常。我们探讨了各种场景,包括表达式抛出、重新抛出和 Nothing 类型。适当的异常处理使您的代码更健壮且易于维护。

作者

我的名字是 Jan Bodnar,我是一位充满激情的程序员,拥有多年的编程经验。自 2007 年以来,我一直在撰写编程文章。到目前为止,我已经撰写了 1400 多篇文章和 8 本电子书。我拥有超过八年的编程教学经验。

列出 所有 Kotlin 教程