Kotlin教程 异常处理

一.异常处理-try-catch

1.简介

try-catch在Java中是一种经典的处理异常的方式,在Kotlin中也可以使用。

2.try-catch

try {//可能抛出异常的代码

    ......

} catch (e: Exception) {//异常处理

    ......

} finally {//无论是否异常都会执行的代码

    ......

}

3.举例

以两个整数相除为例,被除数为0时报错

val divisor = 100
val dividend = 0
val result = try {
    divisor / dividend
} catch (e: Exception) {
    Log.d("协程测试", "异常信息:${e.message}")
} finally {
    Log.d("协程测试", "finally方法...")
}
Log.d("协程测试", "100/0=$result")

4.结果

异常信息:divide by zero

finally方法...

100/0=1

5.结论

故意将被除数入参0,使用try-catch捕获异常,结果如上,虽然没有报错,但是返回的结果是错误的,这显然是不有好的。

二.异常处理-runCatching

1.简介

runCatching是Kotlin较Java特有的一种处理异常的方式,它返回一个Result<T>对象,把异常处理变成了可以链式调用的操作。

2.源码

@InlineOnly
@SinceKotlin("1.3")
public inline fun <T, R> T.runCatching(block: T.() -> R): Result<R> {
    return try {
        Result.success(block())
    } catch (e: Throwable) {
        Result.failure(e)
    }
}

runCatching有两个回调的方法,success&failure。

success:返回正确的内容。没有异常,返回正确值。

failure:返回错误的内容,主要返回异常信息。

3.举例

private fun calculate(divisor: Int, dividend: Int): Result<Int> {
    return runCatching {
        divisor / dividend
    }
}


//正确举例 正确时不做其他处理
val num1 = calculate(100, 5)
num1.onSuccess { content ->
    Log.d("协程测试", "正确 100/5=$content")
}.onFailure { exception ->
    Log.d("协程测试", "错误 100/5= ${exception.message}")
}


//正确举例 正确时修改返回值内容 即输出100/5=21
val num2 = calculate(100, 5)
num2.map { content ->//正确时,操作返回值内容,在onSuccess方法之前执行,走onSuccess回调
    content + 1
}.onSuccess { content ->
    Log.d("协程测试", "正确 100/5=$content")
}.onFailure { exception ->
    Log.d("协程测试", "错误 100/5= ${exception.message}")
}


//错误举例 错误时不做其他处理
val num3 = calculate(100, 0)
num3.onSuccess { content ->
    Log.d("协程测试", "正确 100/0=$content")
}.onFailure { exception ->
    Log.d("协程测试", "错误 100/0= ${exception.message}")
}


//错误举例 不错误时,强制返回20 即输出100/0=20
val num4 = calculate(100, 0)
num4.recover {//失败时,操作返回值内容,在onSuccess方法之前执行,走onSuccess回调
    20
}.onSuccess { content ->
    Log.d("协程测试", "正确 100/0=$content")
}.onFailure { exception ->
    Log.d("协程测试", "错误 100/0= ${exception.message}")
}

4.结果

正确 100/5=20


正确 100/5=21


错误 100/0= divide by zero


正确 100/0=20

5.结论

上述打印的结果可知,runCatching处理异常相当的简单。

<1>.无异常时,回调onSuccess 方法,返回正常的结果。如果想要在无异常时,操作一下返回值,可以在onSuccess方法前重写map方法做些额外的操作。比如

.map { content ->//正确时,操作返回值内容,在onSuccess方法之前执行,走onSuccess回调
    content + 1
}

map方法源码

@InlineOnly
@SinceKotlin("1.3")
public inline fun <R, T> Result<T>.map(transform: (value: T) -> R): Result<R> {
    contract {
        callsInPlace(transform, InvocationKind.AT_MOST_ONCE)
    }
    return when {
        isSuccess -> Result.success(transform(value as T))
        else -> Result(value)
    }
}

在onSuccess方法前重写,可以覆盖原本正确的结果,然后在onSuccess方法中回调。

<2>.有异常时,回调onFailure 方法,返回异常信息。如果想要在有异常时,操作一下返回值,可以在onSuccess方法前重写recover方法,做些额外的操作,使其强制执行onSuccess方法,而不执行onFailure方法。比如

.recover {//失败时,操作返回值内容,在onSuccess方法之前执行,走onSuccess回调
    20
}

recover源码

@InlineOnly
@SinceKotlin("1.3")
public inline fun <R, T : R> Result<T>.recover(transform: (exception: Throwable) -> R): Result<R> {
    contract {
        callsInPlace(transform, InvocationKind.AT_MOST_ONCE)
    }
    return when (val exception = exceptionOrNull()) {
        null -> this
        else -> Result.success(transform(exception))
    }
}

在onSuccess方法前重写,可以让原本发生异常时走onFailure方法改成强制执行onSuccess方法。

6.补充

Result还有几个其他的方法。

<1>.isSuccess / isFailure:用于检查结果是成功还是失败的布尔值。

val num2 = calculate(100, 5)
num2.map { content ->//正确时,操作返回值内容,在onSuccess方法之前执行,走onSuccess回调
    content + 1
}.onSuccess { content ->
    Log.d("协程测试", "正确 100/5=$content")
}.onFailure { exception ->
    Log.d("协程测试", "错误 100/5= ${exception.message}")
}
val isSuccess = num2.isSuccess
Log.d("协程测试", "isSuccess= $isSuccess")



****************************输出***********************************************

正确 100/5=21

isSuccess= true

val num3 = calculate(100, 0)
num3.onSuccess { content ->
    Log.d("协程测试", "正确 100/0=$content")
}.onFailure { exception ->
    Log.d("协程测试", "错误 100/0= ${exception.message}")
}
val isFailure = num3.isFailure
Log.d("协程测试", "isFailure= $isFailure")



***************************************输出**********************************
错误 100/0= divide by zero

isFailure= true

<2>.getOrNull():如果操作成功,返回对应的值;如果失败,则返回 null。

<3>.exceptionOrNull():如果操作失败,返回抛出的异常;如果成功,则返回 null。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值