You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

Kotlin协程中RxJava onError系列方法的替代方案咨询

Kotlin协程中替代RxJava onError系列方法的实现

一、错误时提供默认值的常用方案

除了直接用try...catch,还有这些更简洁的实现方式:

1. 使用runCatching + 结果处理方法

Kotlin标准库的runCatching可以捕获执行块中的异常,返回Result<T>类型,后续通过getOrDefault()、getOrElse()快速设置默认值:

// 单个挂起函数的错误处理
val data = runCatching { fetchDataFromApi() }
    .getOrDefault(defaultData) // 异常时返回预设默认值

// 或根据异常类型自定义默认值逻辑
val data = runCatching { fetchDataFromApi() }
    .getOrElse { exception ->
        if (exception is NetworkException) emptyList() else defaultData
    }

2. 自定义挂起函数扩展(模仿RxJava风格)

如果习惯RxJava的onErrorReturn、onErrorResumeNext语法,可以封装自己的扩展函数:

// 封装挂起函数的异常捕获逻辑
suspend fun <T> suspendCatching(block: suspend () -> T): Result<T> = runCatching { block() }

// 模仿onErrorReturn,直接返回固定默认值
fun <T> Result<T>.onErrorReturn(defaultValue: T): T = getOrDefault(defaultValue)

// 模仿onErrorResumeNext,支持根据异常生成默认值
fun <T> Result<T>.onErrorResumeNext(block: (Throwable) -> T): T = getOrElse(block)

// 使用示例
val data = suspendCatching { fetchDataFromApi() }
    .onErrorReturn(defaultData)

二、RxJava Single.zip的协程等价实现

Single.zip的核心是并行执行多个任务,全部成功后组合结果,任意任务失败则触发错误,协程中可以通过coroutineScope/supervisorScope + async + awaitAll实现,同时结合上述错误处理逻辑。

1. 整体失败时返回默认值(对应Single.zip + onErrorReturn)

如果希望任意一个任务出错,整个组合操作直接返回默认值:

// 原RxJava代码示例
Single.zip(
    singleApiCall1(),
    singleApiCall2(),
    singleApiCall3(),
    { v1, v2, v3 -> CombinedData(v1, v2, v3) }
)
.onErrorReturn { CombinedData(defaultV1, defaultV2, defaultV3) }

// 协程等价实现
val combinedResult = runCatching {
    coroutineScope {
        // 并行启动三个异步任务
        val (v1, v2, v3) = awaitAll(
            async { singleApiCall1().await() },
            async { singleApiCall2().await() },
            async { singleApiCall3().await() }
        )
        CombinedData(v1, v2, v3)
    }
}.getOrDefault(CombinedData(defaultV1, defaultV2, defaultV3))

这里coroutineScope的作用是:如果任意一个async任务抛出异常,会立即取消其他所有子协程并抛出异常,最终被runCatching捕获,返回预设的默认组合值。

2. 单个任务出错时返回默认值(不影响其他任务)

如果希望单个任务失败时用默认值替代,不中断其他任务执行,需要用supervisorScope(不会因单个子协程失败取消其他),并在每个任务内部处理异常:

val combinedResult = supervisorScope {
    val deferred1 = async {
        runCatching { singleApiCall1().await() }.getOrDefault(defaultV1)
    }
    val deferred2 = async {
        runCatching { singleApiCall2().await() }.getOrDefault(defaultV2)
    }
    val deferred3 = async {
        runCatching { singleApiCall3().await() }.getOrDefault(defaultV3)
    }
    // 等待所有任务完成,即使部分任务使用了默认值
    CombinedData(deferred1.await(), deferred2.await(), deferred3.await())
}

也可以封装扩展函数简化代码:

suspend fun <T> Deferred<T>.awaitOrDefault(default: T): T = runCatching { await() }.getOrDefault(default)

// 使用扩展后的代码
val combinedResult = supervisorScope {
    val d1 = async { singleApiCall1().await() }
    val d2 = async { singleApiCall2().await() }
    val d3 = async { singleApiCall3().await() }
    CombinedData(d1.awaitOrDefault(defaultV1), d2.awaitOrDefault(defaultV2), d3.awaitOrDefault(defaultV3))
}

内容的提问来源于stack exchange,提问作者Goltsev Eugene

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.07.16 17:32:38