Either<L, R>:无需异常的类型化错误处理
使用 Either 表示成功与失败,而无需抛出异常。
Either<L, R>:无需异常的类型化错误处理 是 CoddyKit 上的免费 Kotlin Academy 课时。 这是第 1 节课,共 4 节。 你可以在下方免费阅读本课时的完整内容 — 然后在浏览器中使用内置代码编辑器和全天候 AI 导师进行实践。 这是 Kotlin Academy 学习路径的一部分,你的进度在网页和 CoddyKit 应用中同步。 Kotlin Academy 课程共包含 4 节课。
使用异常处理业务逻辑的问题
异常适用于意外故障(空指针、IO 错误)。使用异常表示预期的业务失败(验证失败、“未找到”)会使控制流变得不可见,迫使您在每个调用位置都编写异常捕获代码,并在函数签名中隐藏错误。
什么是 Either<L, R>
Either 是一种和类型,有两种情况:Left(value: L) 按照惯例保存错误,Right(value: R) 按照惯例保存成功值。返回 Either 的函数会在其签名中明确表示可能失败。
Arrow 的 Either
将 Arrow 添加到项目中,即可获得 Either 及其完整的运算符生态:
// build.gradle.kts
implementation("io.arrow-kt:arrow-core:1.2.4")
// Usage
import arrow.core.Either
import arrow.core.left
import arrow.core.right从函数返回 Either
成功时返回 value.right(),失败时返回 error.left()。调用方必须处理这两个分支:
sealed class UserError { object NotFound : UserError(); data class InvalidEmail(val msg: String) : UserError() }
fun findUser(id: Long): Either<UserError, User> =
if (id <= 0) UserError.NotFound.left()
else User(id, "Alice").right()使用 fold 消费 Either
使用 fold(ifLeft, ifRight) 在一个表达式中处理两种情况:
val result = findUser(1L)
val message = result.fold(
ifLeft = { error -> "Error: $error" },
ifRight = { user -> "Found: ${user.name}" }
)
println(message)使用 map 转换 Right 值
map { } 会转换 Right 值,而不会触碰 Left。这使 Either 成为函子,您可以安全地链式执行转换:
val nameResult: Either<UserError, String> = findUser(1L).map { it.name }使用 flatMap 链式处理
flatMap { } 会串联自身返回 Either 的计算步骤。如果任何一步返回 Left,链就会提前结束,错误会直接传播,而不会执行后续步骤:
fun validateEmail(email: String): Either<UserError, String> =
if (email.contains("@")) email.right()
else UserError.InvalidEmail("bad format").left()
fun createUser(email: String): Either<UserError, User> =
validateEmail(email).flatMap { validEmail ->
User(1L, validEmail).right()
}使用 Either.catch 封装异常
Either.catch { } 会执行一个代码块,并将任何异常封装为 Left。请在会抛出异常的旧代码与基于 Either 的领域之间的边界处使用它:
val result: Either<Throwable, User> = Either.catch {
userRepository.findOrThrow(id)
}使用 getOrElse 和 orElse 恢复
getOrElse { default } 会提取 Right 值,或返回默认值。orElse { alternativeEither } 会用另一个计算替换 Left:
val user: User = findUser(0L).getOrElse { User(-1L, "Guest") }
val user2: Either<UserError, User> = findUser(0L).orElse { User(99L, "Default").right() }使用 when 进行模式匹配
可以对密封的、类似 Either 的类使用 when,也可以对 Either 本身使用 is Either.Left / Either.Right,从而穷尽处理所有情况:
when (val r = findUser(1L)) {
is Either.Left -> println("Error: ${r.value}")
is Either.Right -> println("User: ${r.value.name}")
}服务层中的 Either
让存储库函数和服务函数返回 Either。在 Ktor 路由层将其映射为 HTTP 响应,使业务逻辑不受框架关注点影响:
get("/users/{id}") {
val id = call.parameters["id"]?.toLongOrNull() ?: return@get call.respond(HttpStatusCode.BadRequest)
userService.findById(id).fold(
ifLeft = { call.respond(HttpStatusCode.NotFound) },
ifRight = { call.respond(it) }
)
}快速检查
对 Either.Left 值调用 flatMap { } 会发生什么?
回顾:Either<L, R>
关键要点:
Either会在函数签名中明确表示失败路径Right= 成功;Left= 失败(按照惯例)map { }— 转换成功值;flatMap { }— 串联可能失败的计算fold(ifLeft, ifRight)— 在一个表达式中消费两种情况Either.catch { }— 在边界处封装会抛出异常的代码
常见问题解答
「Either<L, R>:无需异常的类型化错误处理」课时是免费的吗?
是的 — 「Either<L, R>:无需异常的类型化错误处理」的完整文本可在网页上免费阅读。要进行交互式练习(内置代码编辑器和全天候 AI 导师)并解锁 Kotlin Academy 课程的其余内容,请升级到 CoddyKit PRO。 Kotlin Academy 课程共包含 4 节课。
「Either<L, R>:无需异常的类型化错误处理」这节课中我会学到什么?
使用 Either 表示成功与失败,而无需抛出异常。 你通过在浏览器中直接运行的动手代码来练习 Kotlin Academy,全天候 AI 导师会在你学习这节课的过程中回答你的问题。
学习 Kotlin Academy 需要有经验吗?
无需任何先前经验。CoddyKit 上的 Kotlin Academy 课程适合初学者到高级学习者,你可以从这里开始或从头开始,按照自己的节奏学习。 这是第 1 节课,共 4 节。
「Either<L, R>:无需异常的类型化错误处理」课时需要多长时间?
大多数 CoddyKit 课程大约需要 5–10 分钟。每节课都很精短且互动,所以你能稳步进步,并在网页和应用中从离开的地方继续。
我能在这节 Kotlin Academy 课中编写并运行代码吗?
能。每节 Kotlin Academy 课都包含内置代码编辑器,你可以在浏览器中直接编写并运行真实代码,并获得即时 AI 反馈 — 无需本地设置。
此课程中的所有课时
- Either :无需异常的类型化错误处理
- Arrow Raise DSL:组合类型化错误
- Option 与 Nullable:如何选择
- 使用 Arrow 核心类型进行函数式领域建模