Kotlin中如何用高阶函数实现支持任意函数的try-catch通用封装
实现方案
核心思路
你不需要为不同参数签名的函数单独重载safeCall,只要让safeCall接收一个无参的普通/挂起lambda表达式作为入参即可。调用方在传入时直接把目标函数的调用逻辑包裹在lambda里,lambda可以自动捕获所有需要的参数,天然适配任意参数数量、参数类型的原函数。
完整代码实现
首先定义通用的Result密封类:
sealed class Result<out T> { data class Success<out T>(val data: T) : Result<T>() data class Error(val exception: Throwable) : Result<Nothing>() }
普通函数版本的safeCall实现:
inline fun <T> safeCall(block: () -> T): Result<T> { return try { Result.Success(block()) } catch (e: Throwable) { // 可在此处添加全局异常处理逻辑,比如日志打印、错误上报 Result.Error(e) } }
如果需要适配协程挂起函数,额外增加挂起重载即可:
suspend inline fun <T> safeCall(crossinline block: suspend () -> T): Result<T> { return try { Result.Success(block()) } catch (e: Throwable) { Result.Error(e) } }
调用示例
先定义你提到的两个测试函数:
// 无参返回String的foo函数,可能抛出异常 fun foo(): String { if (System.currentTimeMillis() % 2 == 0L) throw RuntimeException("foo执行失败") return "foo执行成功" } // 接收String参数返回Boolean的bar函数,可能抛出异常 fun bar(input: String): Boolean { if (input.isEmpty()) throw IllegalArgumentException("input不能为空") return input.length > 3 }
调用方式:
fun main() { // 调用无参的foo val fooResult = safeCall { foo() } when (fooResult) { is Result.Success -> println("foo结果:${fooResult.data}") is Result.Error -> println("foo报错:${fooResult.exception.message}") } // 调用带参的bar,参数直接在lambda中传入即可 val barParam = "test" val barResult = safeCall { bar(barParam) } when (barResult) { is Result.Success -> println("bar结果:${barResult.data}") is Result.Error -> println("bar报错:${barResult.exception.message}") } }
方案优势
- 不管原函数有0个、1个还是N个参数,都可以通过lambda捕获外部参数的方式适配,
safeCall本身不需要感知参数的存在 - inline特性不会带来额外性能损耗,性能和直接在调用处写try-catch完全一致
- 普通函数、挂起函数都可以用相同的调用风格,上手成本极低
内容的提问来源于stack exchange,提问作者bpr10
相关产品推荐
相关产品推荐

