当前位置:网站首页>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] */
}
边栏推荐
- 小程序开发黑马购物商城中遇到的问题
- What are the differences between software testers with a monthly salary of 7K and 25K? Leaders look up to you when they master it
- Redis:Redis的简单使用
- In the face of difficult SQL requirements, HQL is not afraid
- Leetcode 183 Customers who never order (2022.07.02)
- Comment communiquer avec Huawei Cloud IOT via le Protocole mqtt
- Network security - phishing
- Hard core observation 547 large neural network may be beginning to become aware?
- Socket编程
- Modify table structure
猜你喜欢
stm32F407-------IIC通讯协议
A 30-year-old software tester, who has been unemployed for 4 months, is confused and doesn't know what to do?
[fluent] fluent debugging (debug debugging window | viewing mobile phone log information | setting normal breakpoints | setting expression breakpoints)
Bottleneck period must see: how can testers who have worked for 3-5 years avoid detours and break through smoothly
Visualisation de l'ensemble de données au format yolov5 (fichier labelme json)
可视化yolov5格式数据集(labelme json文件)
【Camera专题】OTP数据如何保存在自定义节点中
[shutter] pull the navigation bar sideways (drawer component | pageview component)
[shutter] shutter debugging (debugging fallback function | debug method of viewing variables in debugging | console information)
【Camera专题】手把手撸一份驱动 到 点亮Camera
随机推荐
Everything file search tool
How to refresh the opening amount of Oracle ERP
stm32F407-------ADC
浏览器是如何对页面进行渲染的呢?
Function definition and call, this, strict mode, higher-order function, closure, recursion
Network security - Information Collection
leetcode961. Find the elements repeated N times in the array with length 2n
Custom components, using NPM packages, global data sharing, subcontracting
Visualisation de l'ensemble de données au format yolov5 (fichier labelme json)
Network security - Trojan horse
小程序開發的部分功能
[camera topic] turn a drive to light up the camera
CFdiv2-Fixed Point Guessing-(区间答案二分)
树形结构数据的处理
The technology boss is ready, and the topic of position C is up to you
[shutter] hero animation (hero realizes radial animation | hero component createrecttween setting)
Some functions of applet development
Iptables layer 4 forwarding
File class (check)
Redis:Redis的简单使用