当前位置:网站首页>Exception handling in kotlin process
Exception handling in kotlin process
2022-07-03 02:07:00 【yu-Knight】
List of articles
The necessity of exception handling
- When something unexpected happens to the application , It is very important to provide users with the right experience , One side , It's a terrible experience to witness an application crash , On the other hand , When user operation fails , You must also be able to give correct prompt information .
Abnormal propagation
- There are two forms of coprocessor : Auto propagate exception (launch And actor), Expose exceptions to users (async And produce) When these builders are used to create a root collaboration ( This process is not a child of another process ), The former type of builder , An exception is thrown the first time it occurs , The latter relies on users to end up with abnormal consumption , For example, through await or receive.
@Test
fun `test exception propagation`() = runBlocking<Unit> {
val job = GlobalScope.launch {
try {
throw IndexOutOfBoundsException()
} catch (e: Exception) {
println("Caught IndexOutOfBoundsException")
}
}
job.join()
val deferred = GlobalScope.async {
throw ArithmeticException()
}
try {
deferred.await()
} catch (e: Exception) {
println("Caught ArithmeticException")
}
/** Caught IndexOutOfBoundsException Caught ArithmeticException */
}
Non root coroutine exception
- In the processes created by other processes , The generated exception will always be propagated .
@Test
fun `test exception propagation2`() = runBlocking<Unit> {
val scope = CoroutineScope(Job())
val job = scope.launch {
// If async Throw an exception ,launch Will immediately throw an exception , Instead of calling .await()
async {
throw IllegalArgumentException()
}
}
job.join()
}
Abnormal propagation characteristics
- When a coroutine fails due to an exception , It will propagate the exception and pass it to its parent . Next , The parent will perform the following operations :
- 1. Cancel its own children
- 2. Cancel itself
- 3. Propagate the exception and pass it to its parent
SupervisorJob
- Use SupervisorJob when , The failure of one subprocess will not affect other subprocesses .SupervisorJob Will not propagate exceptions to its parent , It lets the subroutine handle the exception itself .
- This requirement is common in defining jobs in scope UI Components , If any one UI The sub job execution of failed , It is not always necessary to cancel the whole UI Components , But if UI The components were destroyed , Because its result is no longer needed , It is necessary to make all sub jobs fail .
@Test
fun `test SupervisorJob`() = runBlocking<Unit> {
val supervisor = CoroutineScope(SupervisorJob())
val job1 = supervisor.launch {
delay(100)
println("child 1")
throw IllegalArgumentException()
}
val job2 = supervisor.launch {
try {
delay(Long.MAX_VALUE)
} finally {
println("child 2 finished")
}
}
delay(200)
supervisor.cancel()
joinAll(job1, job2)
}
supervisorScope
- When the execution of the job itself fails , All sub jobs will be cancelled
@Test
fun `test SupervisorScope`() = runBlocking<Unit> {
try {
supervisorScope {
val child = launch {
try {
println("The child is sleeping")
delay(Companion.MAX_VALUE)
} finally {
println("The child is cancelled")
}
}
yield()// Use yield Let's give our sub job a chance to print
println("Throwing an exception from the scope")
throw AssertionError()
}
} catch (e: AssertionError) {
println("Caught an assertion error")
}
/** The child is sleeping Throwing an exception from the scope The child is cancelled Caught an assertion erro */
}
Abnormal capture
- Use CoroutineExceptionHandler Catch the exception of the cooperation process .
- When the following conditions are met , The exception will be caught :
1. opportunity : An exception is thrown by a coroutine that automatically throws an exception ( Use launch, instead of async when );
2. Location : stay CoroutineScope Of CoroutineContext Or in a root coroutine (CoroutineScope perhaps supervisorScope Direct subprocess of ) in .
@Test
fun `test CoroutineExceptionHandler`() = runBlocking<Unit> {
val handler = CoroutineExceptionHandler {
_, exception ->
println("Caught $exception")
}
val job = GlobalScope.launch(handler) {
throw AssertionError() // Exception caught
}
val deferred = GlobalScope.async(handler) {
throw ArithmeticException() // Not captured
}
job.join()
deferred.await()
}
@Test
fun `test CoroutineExceptionHandler2`() = runBlocking<Unit> {
val handler = CoroutineExceptionHandler {
_, exception ->
println("Caught $exception")
}
val scope = CoroutineScope(Job())
// It can catch the exception thrown by the subprocess
val job = scope.launch(handler) {
launch {
throw AssertionError()// Throw an exception to the parent process
}
}
job.join()
}
Android Global exception handling in
- The global exception handler can get all unhandled exceptions of the collaboration , However, it cannot catch exceptions , Although it can't prevent the program from crashing , Global exception handlers are still very useful in scenarios such as program debugging and exception reporting .
- We need to be in classpath Create below META-INF/services Catalog , And create one of them called kotlinx.coroutines.CoroutineExceptionHandler The file of , The content of the file is the full class name of our global exception handler .
class GlobalCoroutineExceptionHandler : CoroutineExceptionHandler {
override val key = CoroutineExceptionHandler
override fun handleException(context: CoroutineContext, exception: Throwable) {
Log.d("yuknight", "Unhandled Coroutine Exception:$exception")
}
}
Cancel and exception
- Cancellation is closely related to exceptions , Used internally in the process CancellationException To cancel , This exception will be ignored .
- When the subprocess is cancelled , It will not cancel its parent process .
- If a collaboration encounters CancellationException An exception , It will use this exception to cancel its parent coroutine . When all the child processes of the parent process are finished , Exceptions will be handled by the parent coroutine .
@Test
fun `test cancel and exception`() = runBlocking<Unit> {
val job = launch {
val child = launch {
try {
try {
delay(Long.MAX_VALUE)
} catch (e: Exception) {
e.printStackTrace()
}
} finally {
println("Child is cancelled")
}
}
yield()
println("Cancelling child")
child.cancelAndJoin()
yield()
println("Parent is not cancelled")
}
job.join()
}
@Test
fun `test cancel and exception2`() = runBlocking<Unit> {
val handler = CoroutineExceptionHandler {
_, exception ->
println("Caught $exception")
}
val job = GlobalScope.launch(handler) {
launch {
try {
delay(Long.MAX_VALUE)
} finally {
withContext(NonCancellable) {
println("Children are cancelled, but exception is not handled until all children terminate")
delay(100)
println("The first child finished its non cancellable block")
}
}
}
launch {
delay(10)
println("Second child throws an exception")
throw ArithmeticException()
}
}
job.join()
/** Second child throws an exception Children are cancelled, but exception is not handled until all children terminate The first child finished its non cancellable block Caught java.lang.ArithmeticException */
}
Abnormal aggregation
- When multiple child processes of a process fail due to exceptions , Generally, the first exception is taken for processing . All other exceptions that occur after the first exception , Will be bound to the first exception .
@Test
fun `test exception aggregation`() = runBlocking<Unit> {
val handler = CoroutineExceptionHandler {
_, exception ->
println("Caught $exception ${
exception.suppressed.contentToString()}")
}
val job = GlobalScope.launch(handler) {
launch {
try {
delay(Long.MAX_VALUE)
} finally {
throw ArithmeticException()
}
}
launch {
try {
delay(Long.MAX_VALUE)
} finally {
throw IndexOutOfBoundsException()
}
}
launch {
delay(100)
throw IOException()
}
}
job.join()
/** Caught java.io.IOException [java.lang.ArithmeticException, java.lang.IndexOutOfBoundsException] */
}
边栏推荐
- Network security - firewall
- Caused by: com.fasterxml.jackson.databind.exc.MismatchedInputException: Cannot construct instance o
- Rockchip3399 start auto load driver
- PyTorch 卷积网络正则化 DropBlock
- 詳細些介紹如何通過MQTT協議和華為雲物聯網進行通信
- [fluent] fluent debugging (debug debugging window | viewing mobile phone log information | setting normal breakpoints | setting expression breakpoints)
- DML Foundation
- [shutter] shutter debugging (debugging fallback function | debug method of viewing variables in debugging | console information)
- Summary of ES6 filter() array filtering methods
- DDL basic operation
猜你喜欢
Custom components, using NPM packages, global data sharing, subcontracting
Network security - vulnerabilities and Trojans
His experience in choosing a startup company or a big Internet company may give you some inspiration
Query product cases - page rendering data
小程序开发的部分功能
MySQL学习03
深度(穿透)选择器 ::v-deep/deep/及 > > >
udp接收队列以及多次初始化的测试
How to deal with cache hot key in redis
Deep learning notes (constantly updating...)
随机推荐
The Sandbox阐释对元宇宙平台的愿景
udp接收队列以及多次初始化的测试
[Yu Yue education] China Ocean University job search OMG reference
Iptables layer 4 forwarding
函数的定义和调用、this、严格模式、高阶函数、闭包、递归
CFdiv2-Fixed Point Guessing-(区间答案二分)
树形结构数据的处理
File class (add / delete)
Socket编程
ByteDance data Lake integration practice based on Hudi
Visualisation de l'ensemble de données au format yolov5 (fichier labelme json)
詳細些介紹如何通過MQTT協議和華為雲物聯網進行通信
Cfdiv2 fixed point guessing- (interval answer two points)
疫情當頭,作為Leader如何進行團隊的管理?| 社區征文
全链路数字化转型下,零售企业如何打开第二增长曲线
小程序開發的部分功能
leetcode961. Find the elements repeated N times in the array with length 2n
In the face of difficult SQL requirements, HQL is not afraid
Cfdiv2 Fixed Point Guessing - (2 points for Interval answer)
stm32F407-------ADC