当前位置:网站首页>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] */
}
边栏推荐
- Summary of ES6 filter() array filtering methods
- 疫情當頭,作為Leader如何進行團隊的管理?| 社區征文
- PyTorch 卷积网络正则化 DropBlock
- [Appendix 6 Application of reflection] Application of reflection: dynamic agent
- DQL basic operation
- Network security - man in the middle attack
- DML Foundation
- In the face of difficult SQL requirements, HQL is not afraid
- [Yu Yue education] Jiujiang University material analysis and testing technology reference
- [camera topic] turn a drive to light up the camera
猜你喜欢
微信小程序开发工具 POST net::ERR_PROXY_CONNECTION_FAILED 代理问题
查询商品案例-页面渲染数据
Niuniu's ball guessing game (dynamic planning + prefix influence)
Anna: Beibei, can you draw?
《上市风云》荐书——唯勇气最可贵
Visual yolov5 format data set (labelme JSON file)
Stm32f407 ------- IIC communication protocol
[Appendix 6 Application of reflection] Application of reflection: dynamic agent
小程序开发的部分功能
What are MySQL locks and classifications
随机推荐
What are the differences between software testers with a monthly salary of 7K and 25K? Leaders look up to you when they master it
File class (check)
Visualisation de l'ensemble de données au format yolov5 (fichier labelme json)
缺少库while loading shared libraries: libisl.so.15: cannot open shared object file: No such file
小程序开发黑马购物商城中遇到的问题
Network security - talking about security threats
Socket编程
Machine learning notes (constantly updating...)
【Camera专题】HAL层-addChannel和startChannel简析
Leetcode 183 Customers who never order (2022.07.02)
DQL basic operation
[Yu Yue education] China Ocean University job search OMG reference
微服务组件Sentinel (Hystrix)详细分析
Niuniu's ball guessing game (dynamic planning + prefix influence)
深度(穿透)选择器 ::v-deep/deep/及 > > >
ByteDance data Lake integration practice based on Hudi
[AUTOSAR cantp] -2.11-uds diagnostic response frame data segment data padding data filling and data optimization data optimization (Theory + configuration)
Network security ACL access control list
Internal connection query and external connection
Swift development learning