在Kotlin中你可能会遇到这种情况,莫名其妙catch到一个UndeclaredThrowableException,可是自己抛出的明明是另一个异常!
如果想要拿到原来的异常,这里先介绍三种解决办法,之后详解原理。
获取原始异常的三种方式
- 第一种最直接粗暴,捕获UndeclaredThrowableException,通过UndeclaredThrowableException的getUndeclaredThrowable()方法获取原异常。
try {
TODO()
} catch (e: UndeclaredThrowableException) {
if (e.undeclaredThrowable is CommonException) {
// 拿到原始异常
val commonException = e.undeclaredThrowable as CommonException
throw commonException
}
}
// 显然这种方法并不推荐
- 在抛出异常的方法上声明异常
@Throws(CommonException::class)
fun mayThrowCommonException(){
}
- 如果原始异常是自己定义的异常,那么可以修改异常的定义,使之继承RuntimeException而不是Exception
// 原定义
class CommonException(var code: String, override var message: String) : Exception(message)
// 新定义
class CommonException(var code: String, override var message: String) : RuntimeException(message)
关于更多办法方法一个stack overflow上的答案说得挺好
再来说说为什么
首先,我们要知道Kotlin是没有受检异常的,这是Kotlin在设计上的一个选择,认为受检异常会降低生产力且在提高代码质量上收效甚微1。在Kotlin中你可以随时抛出异常而不用声明。
其次,虽然Kotlin发展迅速,但是如今大火的java框架,很多都是基于代理实现,java中的受检异常强制要求处理,必须catch或显式声明抛出。
那么当你抛出异常的类被java生成的代理类代理,代理对象会调用你真实对象的方法,虽然你在kotlin中抛受检异常没问题,但在代理对象( java )中,相当于你的方法抛出了未声明的受检异常,这在java中是不允许的,于是你就喜提UndeclaredThrowableException。