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
相关产品推荐
相关产品推荐

