Kotlin 中的错误处理:try/catch 与高级技术

面向初学者的在线Python训练器

轻松学习Python,无需理论负担。在浏览器中直接解决带自动检查的实践任务,无需安装任何东西。

开始课程

Kotlin中的高级错误处理:从try/catch到函数式方法



错误处理是开发可靠软件的关键任务之一。在Kotlin中,除了经典的try/catch/finally机制外,还有一整套高级工具:Result、runCatching、sealed class和函数式单子。在本文中,我们将探讨如何超越基本用法,让代码更安全、更易读且更具可预测性。



1. 经典try/catch:何时仍然适用



Kotlin中的基本try/catch是一个可以返回值的表达式。这是它与Java的首要区别。



val result: String = try {    riskyOperation()} catch (e: IOException) {    "I/O error: ${e.message}"} catch (e: Exception) {    "Unknown error: ${e.message}"} finally {    println("The finally block always executes")}


尽管它很简单,但这种方法存在缺点:

  • 异常是一种昂贵的操作(创建堆栈跟踪)。
  • 错误类型在类型级别上未固定——很容易遗漏处理。
  • 当嵌套操作较多时代码会变得冗长。


何时使用try/catch?

  • 处理外部资源时(文件、网络、数据库)。
  • 在库代码中,异常是约定的一部分。
  • 对于无法在本地处理的严重错误。


2. 函数式方法:Result和runCatching



Kotlin提供了内置的Result类,它表示操作的结果可以是成功或失败。这是异常的替代方案,不需要昂贵的堆栈跟踪。



fun divide(a: Int, b: Int): Result<Int> {    return runCatching {        a / b    }}

fun main() { val result = divide(10, 0) result.onSuccess { value -> println("Result: $value") }.onFailure { error -> println("Error: ${error.message}") }}


Result方法

  • getOrNull() — 返回值或null。
  • getOrDefault(default) — 返回值或默认值。
  • map和flatMap — 用于转换链。
  • recover — 错误后恢复。


val safeResult = runCatching { riskyOperation() }    .map { it.toUpperCase() }    .recover { "default_value" }    .getOrDefault("fallback")


重要提示: Result不适合在线程间传递或存储在类字段中——请仅将其作为局部值使用。



3. 密封类:在类型级别建模错误



当你需要明确定义所有可能的状态(成功、各种类型的错误)时,sealed class就能派上用场。这是创建代数数据类型的强大工具。



sealed class NetworkResult<out T> {    data class Success<T>(val data: T) : NetworkResult<T>()    data class Error(val message: String, val code: Int) : NetworkResult<Nothing>()    object Loading : NetworkResult<Nothing>()}

fun fetchUser(id: Int): NetworkResult<User> { return try { val user = api.getUser(id) NetworkResult.Success(user) } catch (e: HttpException) { NetworkResult.Error("Server returned an error", e.code()) } catch (e: Exception) { NetworkResult.Error("Unknown error", 0) }}

fun handleResult(result: NetworkResult<User>) { when (result) { is NetworkResult.Success -> println("User: ${result.data.name}") is NetworkResult.Er

博客

书籍推荐