Java 中的异常处理
日常开发中难免会遇到对异常的处理,我们先来看一段按照 Java 的方式进行的异常处理:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
|
RetrofitUtil.getInstance().callAppData(call, object : NetListener {
override fun onSuccess(message: String) {
Log.d(TAG, "onSuccess() called with: message = $message")
val bean = try {
GsonUtils.fromJson<CollectionBean>(message, CollectionBean::class.java)
} catch (e: Exception) {
null
}
// showUI
}
override fun onFailed(message: String?) {
Log.d(TAG, "onFailed() called with: message = $message")
}
})
|
Kotlin 中的异常处理
这是一段 Kotlin 里面的代码,然后我们针对服务器返回的 message Json 进行 Bean 对象的转换,由于服务器返回的数据可能会和原初定义的不一样,所以我们在这里进行的 try catch 的处理。这是 Java 处理异常的方式, 但是我们已经使用 Kotlin 语言, 可以使用 Kotlin 提供的方式,会更加的简便,代码的可读性也会更好,看下是如何实现的,以及可以有哪些扩展:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
|
RetrofitUtil.getInstance().callAppData(call, object : NetListener {
override fun onSuccess(message: String) {
Log.d(TAG, "onSuccess() called with: message = $message")
val result = message.runCatching {
val bean = GsonUtils.fromJson<CollectionBean>(message, CollectionBean::class.java)
return@runCatching bean
}.onSuccess {
Log.i(TAG, "onSuccess: ")
}.onFailure {
Log.i(TAG, "onFailure: ")
}
val orNull = result.getOrNull()
val defaultValue = result.getOrDefault(CollectionBean())
val orThrow = result.getOrThrow()
val result3 = result.getOrElse {
Log.i(TAG, "onFail: 异常了")
}
}
override fun onFailed(message: String?) {
Log.d(TAG, "onFailed() called with: message = $message")
}
})
|
在 Kotlin 中使用异常处理的方式是使用 runCatching 函数,这其实是一个高阶函数。这里先简单介绍一下这些 API 稍后看下源码具体是如何实现的这个部分。首先在 runCatching 高阶函数的代码块中,这个部分就已经进行了 try catch 包裹的处理,同时还实现了 onSuccess 和 onFailure 高阶函数,实际业务需求可以在这里做成功和失败的逻辑处理,这里我只是做了日志的打印。
runCatching 函数返回的是一个 Result 类,Result 类中,一共定义了如上述的 4 个方法:
- 其中 getOrNull 返回的是 runCatching 中处理的结果,是一个可空类型的,比如这里我返回的是 CollectionBean 类
- getOrDefault 返回的是一个不可空的类型,调用的时候需要传递默认值,为 null 的时候会返回默认值
- getOrThrow 未发生的异常返回的是 runCatching 中处理的结果,如果 runCatching 中发生了异常,调用这个 API 会抛出异常
- getOrElse 返回处理的结果,或者是异常自己处理
源码分析
1.runCatching 的实现
1
2
3
4
5
6
7
8
9
|
@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 是一个内联的高阶函数,返回了一个 Result 类,函数里面对回调出去的 lambda 表达式进行了 try catch 的处理。返回的内容使用 Result.success 和 Result.failure 进行的包裹
2.getOrNull
1
2
3
4
5
6
7
|
@InlineOnly
public inline fun getOrNull(): T? =
when {
isFailure -> null
else -> value as T
}
}
|
异常的情况返回 null ,要么就是返回 value, value 是 Result 的一个属性,也就是上面使用 Result.success(block()) 中返回的结果
3.getOrDefault
1
2
3
4
|
public inline fun <R, T : R> Result<T>.getOrDefault(defaultValue: R): R {
if (isFailure) return defaultValue
return value as T
}
|
如果是异常的情况返回默认值,要么返回的是 value
4.getOrElse
1
2
3
4
5
6
7
8
9
|
public inline fun <R, T : R> Result<T>.getOrElse(onFailure: (exception: Throwable) -> R): R {
contract {
callsInPlace(onFailure, InvocationKind.AT_MOST_ONCE)
}
return when (val exception = exceptionOrNull()) {
null -> value as T
else -> onFailure(exception)
}
}
|
先看看 exceptionOrNull 处理的是什么:
1
2
3
4
5
|
public fun exceptionOrNull(): Throwable? =
when (value) {
is Failure -> value.exception
else -> null
}
|
exceptionOrNull 返回的是: 如果是发生了异常返回异常类, 否则返回 null, 所以 getOrElse 里面返回的是: 异常情况下,返回异常类,否则返回处理的结果 value