RuntimeException 处理最佳实践
RuntimeException handling best practices
RuntimeExceptions 应该表示编程错误,我希望我的应用程序在我的可观察对象中的某些东西抛出 RuntimeException 时崩溃。
最好的方法是什么?现在我正在考虑这个解决方案(它是 Kotlin,但我希望它是可以理解的)
fun <T> Observable<T>.subscribeCrashOnRuntimeException(onNext: (T) -> Unit, onError: (Throwable) -> Unit) {
this.subscribe({
onNext(it)
}, { e ->
if (e is RuntimeException) {
throw e
} else {
onError(e)
}
})
}
fun usageExample() {
val observable = Observable.just(1)
observable.subscribeCrashOnRuntimeExceptions(
{ next -> Log.d("TAG", "next: $next") },
{ e -> Log.d("TAG", "error: $e") }
)
}
但我对此表示怀疑。例如,使用此解决方案很难偶尔 "catch" 特定的 RuntimeExceptions。也许有一种众所周知的方法来处理我不知道如何处理的情况 google?
我认为处理运行时(又名未经检查)或常规(又名检查)异常应该没有太大区别。两者现在都被广泛使用,并且可以根据特定情况恢复或不恢复。
处理错误的反应方式有:
- 通过
onErrorResumeNext
或 onErrorReturn
运算符;这些允许检查错误并可能从中恢复
- 通过
retry*
运算符家族;这些允许检查错误并可能通过re-subscribing(例如重试网络调用) 从错误中恢复
- 通过
onError
订阅者的回调;顺便说一句,如果你不提供这样的回调,错误将以 Java 的方式正常 re-thrown,所以你的程序 将 崩溃
相关主题:
还要注意以常规 Java 方式抛出异常的缺点:
- 消息处理过程中的调用栈与定义消息处理规则时的调用栈不同;这意味着可能很难捕获此类异常,也很难解释堆栈跟踪
- 调度程序捕获的异常可能不会导致程序终止;也就是说,您的程序可能最终会挂在损坏的状态
示例代码
Observable.fromCallable(() -> {
...
if (ok) return "Success!";
else throw new RuntimeException("Failure at source");
})
.map(s -> {
... processing is bypassed in case of an error
})
.map(s -> {
...
if (...) return s.upperCase();
else throw new RuntimeException("Failure during processing");
})
.onErrorReturn(e -> {
if (e.getMessage().contains("processing"))
return "Recovered";
throw Exceptions.propagate(e); // let it continue as an error
})
.subscribe(s -> println("got result: " + s),
e -> println("got error: " + e);
所有异常都被 RxJava 捕获并沿着定义的路径传递。
onError*
运算符就像中间 catch
块。
订阅者的 onError
回调就像 top-level catch
块一样。
有关该主题的更多链接:
RuntimeExceptions 应该表示编程错误,我希望我的应用程序在我的可观察对象中的某些东西抛出 RuntimeException 时崩溃。
最好的方法是什么?现在我正在考虑这个解决方案(它是 Kotlin,但我希望它是可以理解的)
fun <T> Observable<T>.subscribeCrashOnRuntimeException(onNext: (T) -> Unit, onError: (Throwable) -> Unit) {
this.subscribe({
onNext(it)
}, { e ->
if (e is RuntimeException) {
throw e
} else {
onError(e)
}
})
}
fun usageExample() {
val observable = Observable.just(1)
observable.subscribeCrashOnRuntimeExceptions(
{ next -> Log.d("TAG", "next: $next") },
{ e -> Log.d("TAG", "error: $e") }
)
}
但我对此表示怀疑。例如,使用此解决方案很难偶尔 "catch" 特定的 RuntimeExceptions。也许有一种众所周知的方法来处理我不知道如何处理的情况 google?
我认为处理运行时(又名未经检查)或常规(又名检查)异常应该没有太大区别。两者现在都被广泛使用,并且可以根据特定情况恢复或不恢复。
处理错误的反应方式有:
- 通过
onErrorResumeNext
或onErrorReturn
运算符;这些允许检查错误并可能从中恢复 - 通过
retry*
运算符家族;这些允许检查错误并可能通过re-subscribing(例如重试网络调用) 从错误中恢复
- 通过
onError
订阅者的回调;顺便说一句,如果你不提供这样的回调,错误将以 Java 的方式正常 re-thrown,所以你的程序 将 崩溃
相关主题:
还要注意以常规 Java 方式抛出异常的缺点:
- 消息处理过程中的调用栈与定义消息处理规则时的调用栈不同;这意味着可能很难捕获此类异常,也很难解释堆栈跟踪
- 调度程序捕获的异常可能不会导致程序终止;也就是说,您的程序可能最终会挂在损坏的状态
示例代码
Observable.fromCallable(() -> {
...
if (ok) return "Success!";
else throw new RuntimeException("Failure at source");
})
.map(s -> {
... processing is bypassed in case of an error
})
.map(s -> {
...
if (...) return s.upperCase();
else throw new RuntimeException("Failure during processing");
})
.onErrorReturn(e -> {
if (e.getMessage().contains("processing"))
return "Recovered";
throw Exceptions.propagate(e); // let it continue as an error
})
.subscribe(s -> println("got result: " + s),
e -> println("got error: " + e);
所有异常都被 RxJava 捕获并沿着定义的路径传递。
onError*
运算符就像中间 catch
块。
订阅者的 onError
回调就像 top-level catch
块一样。
有关该主题的更多链接: