ZetCode

Kotlin Try/Catch/Finally

最后修改于 2025 年 4 月 19 日

Kotlin 的异常处理机制提供了处理错误的强大方法。try/catch/finally 关键字构成了异常处理的核心。本教程通过实际示例深入探讨了这些关键字。

基本定义

try 块包含可能抛出异常的代码。catch 块处理特定的异常。finally 块无论是否发生异常都会执行。它们共同提供了全面的错误处理。

基本的 Try/Catch

最简单的形式是使用 try 和单个 catch 块。这会捕获特定类型的异常。本例演示了处理 NumberFormatException。

BasicTryCatch.kt
package com.zetcode

fun main() {

    try {
        val num = "abc".toInt()
    } catch (e: NumberFormatException) {
        println("Cannot convert to number: ${e.message}")
    }
}

在这里,我们尝试将一个非数字字符串转换为整数。这会抛出 NumberFormatException,我们捕获并处理它。catch 块打印一条错误消息,其中包含来自异常的详细信息。

在 Kotlin 中处理多个异常

在 Kotlin 中,多个 catch 块允许您有效地处理特定类型的异常。这在不同操作可能抛出各种异常的应用程序中特别有用。考虑一个从文件读取数据并进行处理的示例。在此工作流程中,可能存在文件未找到错误或数据计算期间的算术错误等情况。使用多个 catch 块可确保每个错误都得到适当处理。

MultipleCatchExample.kt
package com.example.multiplecatch

import java.io.File

fun main() {

    try {
        // Attempting to read a file that might not exist
        val fileContent = File("data.txt").readText()
        println("File content: $fileContent")

        // Performing a calculation that might lead to division by zero
        val numbers = fileContent.split(",").map { it.toInt() }
        val result = numbers[0] / numbers[1]
        println("Calculation result: $result")
    } catch (e: java.io.FileNotFoundException) {
        println("Error: The specified file could not be found.")
    } catch (e: ArithmeticException) {
        println("Error: Division by zero is not permitted.")
    } catch (e: Exception) {
        println("Error: An unexpected exception occurred.")
    }
}

在上面的代码中,我们演示了两种不同的异常处理场景

首先,当尝试读取不存在的文件时,可能会发生 java.io.FileNotFoundException。此 catch 块确保程序可以优雅地通知用户,而不会崩溃。其次,如果在除法运算中除数为零,则可能会触发 ArithmeticException。捕获此异常允许程序解决数学错误并继续运行。

最后,一个通用的 catch 块确保有效地管理任何其他不可预见的异常。通过使用特定的 catch 块,开发人员可以为单个错误类型提供清晰而有意义的反馈,而通用的 catch 块充当意外问题的安全网。

Finally 块

finally 块无论是否发生异常都会执行。它通常用于清理操作。此示例显示了带有文件操作的 finally。

FinallyBlock.kt
package com.zetcode

import java.io.File

fun main() {

    val file = File("nonexistent.txt")
    try {
        val contents = file.readText()
        println(contents)
    } catch (e: Exception) {
        println("Error reading file: ${e.message}")
    } finally {
        println("Cleanup operations complete")
    }
}

代码尝试读取一个不存在的文件,从而导致异常。catch 块处理该错误。finally 块无论如何都会执行,执行清理操作。这确保了资源得到正确释放。

Try 作为一个表达式

在 Kotlin 中,try 可以用作返回值的表达式。try 或 catch 中的最后一个表达式成为返回值。此示例演示了此功能。

TryExpression.kt
package com.zetcode

fun parseNumber(str: String): Int? {
    return try {
        str.toInt()
    } catch (e: NumberFormatException) {
        null
    }
}

fun main() {

    val num1 = parseNumber("123")
    val num2 = parseNumber("abc")
    
    println(num1) // Output: 123
    println(num2) // Output: null
}

parseNumber 函数将 try 用作表达式。如果成功,它将返回解析后的整数。如果失败,它将返回 null。这种模式在 Kotlin 中对于安全的解析操作很常见。

嵌套 Try/Catch

try 块可以嵌套以处理不同级别的异常。内部 catch 块首先处理特定的异常。外部块处理更一般的情况。

NestedTry.kt
package com.zetcode

fun main() {

    try {
        try {
            val num = "abc".toInt()
        } catch (e: NumberFormatException) {
            println("Inner catch: Number format error")
            throw e // Re-throw the exception
        }
    } catch (e: Exception) {
        println("Outer catch: General error")
    }
}

内部 try 尝试字符串转换,但失败了。内部 catch 处理 NumberFormatException 并重新抛出它。外部 catch 然后处理重新抛出的异常。这显示了异常传播。

自定义异常

您可以在 Kotlin 中定义和抛出自定义异常。自定义异常应该扩展 Exception 类。此示例显示了自定义验证异常。

CustomException.kt
package com.zetcode

class ValidationException(message: String) : Exception(message)

fun validateAge(age: Int) {
    if (age < 0) {
        throw ValidationException("Age cannot be negative")
    }
}

fun main() {

    try {
        validateAge(-5)
    } catch (e: ValidationException) {
        println("Validation failed: ${e.message}")
    }
}

我们定义了一个 ValidationException 类,它扩展了 Exception。validateAge 函数为负年龄抛出此异常。main 函数捕获并适当地处理自定义异常。

Try With Resources

Kotlin 没有像 Java 那样的 try-with-resources,但是 use 函数提供了类似的功能。它会在执行后自动关闭资源。此示例演示了使用 use 的文件处理。

TryWithResources.kt
package com.zetcode

import java.io.File

fun main() {

    try {
        File("example.txt").bufferedReader().use { reader ->
            println(reader.readText())
        }
    } catch (e: Exception) {
        println("Error reading file: ${e.message}")
    }
}

use 函数确保自动关闭 BufferedReader。文件内容在 lambda 中读取。任何异常都将在外部 try 块中捕获。这是 Kotlin 的惯用资源管理方法。

异常处理最佳实践

来源

Kotlin 异常文档

本教程深入介绍了 Kotlin 的 try/catch/finally 关键字。我们探讨了基本用法、多个 catch 块、finally 和自定义异常。适当的异常处理使您的代码更健壮且更易于维护。

作者

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

列出 所有 Kotlin 教程