日本免费高清视频-国产福利视频导航-黄色在线播放国产-天天操天天操天天操天天操|www.shdianci.com

學(xué)無(wú)先后,達(dá)者為師

網(wǎng)站首頁(yè) 編程語(yǔ)言 正文

Kotlin?try?catch異常處理i詳解_Android

作者:且聽(tīng)真言 ? 更新時(shí)間: 2022-12-23 編程語(yǔ)言

一、cancel()無(wú)效

當(dāng)協(xié)程任務(wù)被取消的時(shí)候,它的內(nèi)部是會(huì)產(chǎn)生一個(gè) CancellationException 的。而協(xié)程的結(jié)構(gòu)化并發(fā),最大的優(yōu)勢(shì)就在于:如果我們?nèi)∠烁竻f(xié)程,子協(xié)程也會(huì)跟著被取消。

1.cancel()不被響應(yīng)

      val job = launch(Dispatchers.Default) {
            var i = 0
            while (true) {
                Thread.sleep(500L)
                i++
                println("i =$i")
            }
        }
        delay(2000L)
        job.cancel()
        job.join()
        println("END")
    }
Log

i =1
i =2
i =3
i =4
i =5
i =6
i =7
i =8
i =9
i =10
i =11
i =12
......
程序無(wú)法停止

上面的程序無(wú)法停止,協(xié)程任務(wù)的取消,需要互相協(xié)作。協(xié)程外部取消,協(xié)程內(nèi)部需要做出響應(yīng)才行。當(dāng)我們調(diào)用 job.cancel() 以后,協(xié)程任務(wù)已經(jīng)不是活躍狀態(tài)了,但代碼并沒(méi)有把 isActive 作為循環(huán)條件,因此協(xié)程無(wú)法真正取消。

可以在協(xié)程體中加入狀態(tài)判斷:

 runBlocking {
        val job = launch(Dispatchers.Default) {
            var i = 0
            while (isActive) {
                Thread.sleep(500L)
                i++
                println("i =$i")
            }
        }
        delay(2000L)
        job.cancel()
        job.join()
        println("END")
    }

Log
?
i =1
i =2
i =3
i =4
END
?
Process finished with exit code 0

把 while 循環(huán)的條件改成了 while (isActive),這就意味著,只有協(xié)程處于活躍狀態(tài)的時(shí)候,才會(huì)繼續(xù)執(zhí)行循環(huán)體內(nèi)部的代碼。協(xié)程的取消需要內(nèi)部的配合。

2.結(jié)構(gòu)被破壞

協(xié)程是結(jié)構(gòu)化的,當(dāng)我們?nèi)∠竻f(xié)程的時(shí)候,子協(xié)程也會(huì)跟著被取消。

但是特殊情況是嵌套創(chuàng)建的子協(xié)程并不會(huì)跟隨父協(xié)程一起取消。

 runBlocking {
        val parentJob = launch(fixedDispatcher) {
            launch(Job()) {
                var i = 0
                while (isActive) {
                    Thread.sleep(500L)
                    i++
                    println("First i:$i")
                }
            }
            launch {
                var i = 0
                while (isActive) {
                    Thread.sleep(500L)
                    i++
                    println("Second i:$i")
                }
            }
        }
        delay(2000L)
        parentJob.cancel()
        parentJob.join()
        println("End")
    }

Log
?
Second i:1
First i:1
First i:2
Second i:2
Second i:3
First i:3
Second i:4
First i:4
End
First i:5
First i:6
First i:7
First i:8
First i:9
First i:10
First i:11
First i:12
First i:13
First i:14
First i:15
......

可以發(fā)現(xiàn),創(chuàng)建子協(xié)程的時(shí)候,使用了 launch(Job()){},就打破了原有的協(xié)程結(jié)構(gòu)。因?yàn)?launch(Job()){}創(chuàng)建的協(xié)程的父 Job 是在 launch 當(dāng)中傳入的 Job() 對(duì)象。所以調(diào)用 parentJob.cancel() 的時(shí)候,無(wú)法銷(xiāo)毀該協(xié)程。

可以按如下修改:

 runBlocking {
        val parentJob = launch(fixedDispatcher) {
            launch {
                var i = 0
                while (isActive) {
                    Thread.sleep(500L)
                    i++
                    println("First i:$i")
                }
            }
            launch {
                var i = 0
                while (isActive) {
                    Thread.sleep(500L)
                    i++
                    println("Second i:$i")
                }
            }
        }
        delay(2000L)
        parentJob.cancel()
        parentJob.join()
        println("End")
    }

First i:1
Second i:1
First i:2
Second i:2
First i:3
Second i:3
First i:4
Second i:4
End

parentJob 與它內(nèi)部的子協(xié)程之間都是父子關(guān)系,因此它們兩個(gè)都是會(huì)響應(yīng)協(xié)程取消的事件的。不要輕易打破協(xié)程的父子結(jié)構(gòu)!

3.未正確處理 CancellationException

對(duì)于 Kotlin 提供的掛起函數(shù),可以自動(dòng)響應(yīng)協(xié)程的取消。

例如:

    runBlocking {
        val parentJob = launch(Dispatchers.Default) {
            launch {
                var i = 0
                while (true) {
                    delay(500L)
                    i++
                    println("First i = $i")
                }
            }
            launch {
                var i = 0
                while (true) {
                    delay(500L)
                    i++
                    println("Second i = $i")
                }
            }
        }
        delay(2000L)
        parentJob.cancel()
        parentJob.join()
        println("End")
    }

First i = 1
Second i = 1
First i = 2
Second i = 2
First i = 3
Second i = 3
End
?
Process finished with exit code 0

delay() 函數(shù)可以自動(dòng)檢測(cè)當(dāng)前的協(xié)程是否已經(jīng)被取消,如果已經(jīng)被取消的話,它會(huì)拋出一個(gè) CancellationException,從而終止當(dāng)前的協(xié)程。

runBlocking {
        val parentJob = launch(Dispatchers.Default) {
            launch {
                var i = 0
                while (true) {
                    try {
                        delay(500L)
                    } catch (e: CancellationException) {
                        println("Catch CancellationException")
                        throw e
                    }
                    i++
                    println("First i =$i")
                }
            }
            launch {
                var i = 0
                while (true) {
                    delay(500L)
                    i++
                    println("Second i = $i")
                }
            }
        }
        delay(2000L)
        parentJob.cancel()
        parentJob.join()
        println("END")
    }

Log:
?
First i =1
Second i = 1
First i =2
Second i = 2
First i =3
Second i = 3
Catch CancellationException
END
?
Process finished with exit code 0

try-catch 包裹了 delay() 以后,打印出“Catch CancellationException”,這就說(shuō)明 delay() 確實(shí)可以自動(dòng)響應(yīng)協(xié)程的取消,并且產(chǎn)生 CancellationException 異常。

注意:捕獲了 CancellationException 以后沒(méi)有重新拋出去,就導(dǎo)致子協(xié)程無(wú)法正常取消。

runBlocking {
        val parentJob = launch(Dispatchers.Default) {
            launch {
                var i = 0
                while (true) {
                    try {
                        delay(500L)
                    } catch (e: CancellationException) {
                        println("Catch CancellationException")
                        //throw e
                    }
                    i++
                    println("First i =$i")
                }
            }
            launch {
                var i = 0
                while (true) {
                    delay(500L)
                    i++
                    println("Second i = $i")
                }
            }
        }
        delay(2000L)
        parentJob.cancel()
        parentJob.join()
        println("END")
    }

......
First i =656179
Catch CancellationException
First i =656180
Catch CancellationException
First i =656181
Catch CancellationException
First i =656182
Catch CancellationException
First i =656183
Catch CancellationException
.....

所以,捕獲了 CancellationException 以后,要考慮是否應(yīng)該重新拋出來(lái)。

二、try-catch不起作用

runBlocking {
        try {
            launch {
                delay(100L)
                1 / 0
            }
        } catch (e: Exception) {
            println("catch: $e")
        }
        delay(500L)
        println("End")
    }

Log
Exception in thread "main" java.lang.ArithmeticException: / by zero
?? ?at com.example.myapplication.testcoroutinue.TestTryCatchKt$testTryCatch8$1$1.invokeSuspend(TestTryCatch.kt:225)
?? ?at kotlin.coroutines.jvm.internal.BaseContinuationImpl.resumeWith(ContinuationImpl.kt:33)
?? ?at kotlinx.coroutines.DispatchedTaskKt.resume(DispatchedTask.kt:234)
?? ?at kotlinx.coroutines.DispatchedTaskKt.dispatch(DispatchedTask.kt:166)
?? ?at kotlinx.coroutines.CancellableContinuationImpl.dispatchResume(CancellableContinuationImpl.kt:397)
?? ?at kotlinx.coroutines.CancellableContinuationImpl.resumeImpl(CancellableContinuationImpl.kt:431)
?? ?at kotlinx.coroutines.CancellableContinuationImpl.resumeImpl$default(CancellableContinuationImpl.kt:420)
?? ?at kotlinx.coroutines.CancellableContinuationImpl.resumeUndispatched(CancellableContinuationImpl.kt:518)
?? ?at kotlinx.coroutines.EventLoopImplBase$DelayedResumeTask.run(EventLoop.common.kt:494)
?? ?at kotlinx.coroutines.EventLoopImplBase.processNextEvent(EventLoop.common.kt:279)
?? ?at kotlinx.coroutines.BlockingCoroutine.joinBlocking(Builders.kt:85)
?? ?at kotlinx.coroutines.BuildersKt__BuildersKt.runBlocking(Builders.kt:59)
?? ?at kotlinx.coroutines.BuildersKt.runBlocking(Unknown Source)
?? ?at kotlinx.coroutines.BuildersKt__BuildersKt.runBlocking$default(Builders.kt:38)
?? ?at kotlinx.coroutines.BuildersKt.runBlocking$default(Unknown Source)
?? ?at com.example.myapplication.testcoroutinue.TestTryCatchKt.testTryCatch8(TestTryCatch.kt:221)
?? ?at com.example.myapplication.testcoroutinue.TestTryCatchKt.main(TestTryCatch.kt:15)
?? ?at com.example.myapplication.testcoroutinue.TestTryCatchKt.main(TestTryCatch.kt)
Process finished with exit code 1

可以發(fā)現(xiàn):try-catch 并沒(méi)有成功捕獲異常,程序等待了 100 毫秒左右,最終還是崩潰了。

使用async

runBlocking {
        var deffered: Deferred<Any>? = null
        try {
            deffered = async {
                delay(100L)
                1 / 0
            }
        } catch (e: ArithmeticException) {
            println("Catch:$e")
        }
        deffered?.await()
        println("End")
    }

Exception in thread "main" java.lang.ArithmeticException: / by zero
?? ?at com.example.myapplication.testcoroutinue.TestTryCatchKt$testTryCatch9$1$1.invokeSuspend(TestTryCatch.kt:242)
?? ?at kotlin.coroutines.jvm.internal.BaseContinuationImpl.resumeWith(ContinuationImpl.kt:33)
?? ?at kotlinx.coroutines.DispatchedTaskKt.resume(DispatchedTask.kt:234)
?? ?at kotlinx.coroutines.DispatchedTaskKt.dispatch(DispatchedTask.kt:166)
?? ?at kotlinx.coroutines.CancellableContinuationImpl.dispatchResume(CancellableContinuationImpl.kt:397)
?? ?at kotlinx.coroutines.CancellableContinuationImpl.resumeImpl(CancellableContinuationImpl.kt:431)
?? ?at kotlinx.coroutines.CancellableContinuationImpl.resumeImpl$default(CancellableContinuationImpl.kt:420)
?? ?at kotlinx.coroutines.CancellableContinuationImpl.resumeUndispatched(CancellableContinuationImpl.kt:518)
?? ?at kotlinx.coroutines.EventLoopImplBase$DelayedResumeTask.run(EventLoop.common.kt:494)
?? ?at kotlinx.coroutines.EventLoopImplBase.processNextEvent(EventLoop.common.kt:279)
?? ?at kotlinx.coroutines.BlockingCoroutine.joinBlocking(Builders.kt:85)
?? ?at kotlinx.coroutines.BuildersKt__BuildersKt.runBlocking(Builders.kt:59)
?? ?at kotlinx.coroutines.BuildersKt.runBlocking(Unknown Source)
?? ?at kotlinx.coroutines.BuildersKt__BuildersKt.runBlocking$default(Builders.kt:38)
?? ?at kotlinx.coroutines.BuildersKt.runBlocking$default(Unknown Source)
?? ?at com.example.myapplication.testcoroutinue.TestTryCatchKt.testTryCatch9(TestTryCatch.kt:237)
?? ?at com.example.myapplication.testcoroutinue.TestTryCatchKt.main(TestTryCatch.kt:16)
?? ?at com.example.myapplication.testcoroutinue.TestTryCatchKt.main(TestTryCatch.kt)
Process finished with exit code 1

當(dāng)協(xié)程體當(dāng)中的“1/0”執(zhí)行的時(shí)候,程序已經(jīng)跳出 try-catch 的作用域了,所以 try-catch失效。

把 try-catch 挪到 launch{} 協(xié)程體內(nèi)部。可以正常捕獲到 ArithmeticException 這個(gè)異常了。

runBlocking {
        var deffered: Deferred<Any>? = null
        deffered = async {
            try {
                delay(100L)
                1 / 0
            } catch (e: ArithmeticException) {
                println("Catch:$e")
            }
        }
        deffered.await()
        println("End")
    }

Log
?
Catch:java.lang.ArithmeticException: / by zero
End
?
Process finished with exit code 0

注意:不要用 try-catch 直接包裹 launch、async。

使用 try-catch 包裹“deferred.await()”。

例:

runBlocking {
        var deffered = async {
            delay(100L)
            1 / 0
        }
        try {
            deffered.await()
        } catch (e: Exception) {
            println("Catch:$e")
        }
        println("End")
    }

atch:java.lang.ArithmeticException: / by zero
End
Exception in thread "main" java.lang.ArithmeticException: / by zero
?? ?at com.example.myapplication.testcoroutinue.TestTryCatchKt$testTryCatch11$1$deffered$1.invokeSuspend(TestTryCatch.kt:275)
?? ?at kotlin.coroutines.jvm.internal.BaseContinuationImpl.resumeWith(ContinuationImpl.kt:33)
?? ?at kotlinx.coroutines.DispatchedTaskKt.resume(DispatchedTask.kt:234)
?? ?at kotlinx.coroutines.DispatchedTaskKt.dispatch(DispatchedTask.kt:166)
?? ?at kotlinx.coroutines.CancellableContinuationImpl.dispatchResume(CancellableContinuationImpl.kt:397)
?? ?at kotlinx.coroutines.CancellableContinuationImpl.resumeImpl(CancellableContinuationImpl.kt:431)
?? ?at kotlinx.coroutines.CancellableContinuationImpl.resumeImpl$default(CancellableContinuationImpl.kt:420)
?? ?at kotlinx.coroutines.CancellableContinuationImpl.resumeUndispatched(CancellableContinuationImpl.kt:518)
?? ?at kotlinx.coroutines.EventLoopImplBase$DelayedResumeTask.run(EventLoop.common.kt:494)
?? ?at kotlinx.coroutines.EventLoopImplBase.processNextEvent(EventLoop.common.kt:279)
?? ?at kotlinx.coroutines.BlockingCoroutine.joinBlocking(Builders.kt:85)
?? ?at kotlinx.coroutines.BuildersKt__BuildersKt.runBlocking(Builders.kt:59)
?? ?at kotlinx.coroutines.BuildersKt.runBlocking(Unknown Source)
?? ?at kotlinx.coroutines.BuildersKt__BuildersKt.runBlocking$default(Builders.kt:38)
?? ?at kotlinx.coroutines.BuildersKt.runBlocking$default(Unknown Source)
?? ?at com.example.myapplication.testcoroutinue.TestTryCatchKt.testTryCatch11(TestTryCatch.kt:272)
?? ?at com.example.myapplication.testcoroutinue.TestTryCatchKt.main(TestTryCatch.kt:16)
?? ?at com.example.myapplication.testcoroutinue.TestTryCatchKt.main(TestTryCatch.kt)
?
Process finished with exit code 1

await() 如果不調(diào)用的話,async 當(dāng)中的異常是否發(fā)生?

runBlocking {
        var deffered = async {
            delay(100L)
            1 / 0
        }
        delay(500L)
        println("End")
    }

Exception in thread "main" java.lang.ArithmeticException: / by zero
?? ?at com.example.myapplication.testcoroutinue.TestTryCatchKt$testTryCatch12$1$deffered$1.invokeSuspend(TestTryCatch.kt:290)
?? ?at kotlin.coroutines.jvm.internal.BaseContinuationImpl.resumeWith(ContinuationImpl.kt:33)
?? ?at kotlinx.coroutines.DispatchedTaskKt.resume(DispatchedTask.kt:234)
?? ?at kotlinx.coroutines.DispatchedTaskKt.dispatch(DispatchedTask.kt:166)
?? ?at kotlinx.coroutines.CancellableContinuationImpl.dispatchResume(CancellableContinuationImpl.kt:397)
?? ?at kotlinx.coroutines.CancellableContinuationImpl.resumeImpl(CancellableContinuationImpl.kt:431)
?? ?at kotlinx.coroutines.CancellableContinuationImpl.resumeImpl$default(CancellableContinuationImpl.kt:420)
?? ?at kotlinx.coroutines.CancellableContinuationImpl.resumeUndispatched(CancellableContinuationImpl.kt:518)
?? ?at kotlinx.coroutines.EventLoopImplBase$DelayedResumeTask.run(EventLoop.common.kt:494)
?? ?at kotlinx.coroutines.EventLoopImplBase.processNextEvent(EventLoop.common.kt:279)
?? ?at kotlinx.coroutines.BlockingCoroutine.joinBlocking(Builders.kt:85)
?? ?at kotlinx.coroutines.BuildersKt__BuildersKt.runBlocking(Builders.kt:59)
?? ?at kotlinx.coroutines.BuildersKt.runBlocking(Unknown Source)
?? ?at kotlinx.coroutines.BuildersKt__BuildersKt.runBlocking$default(Builders.kt:38)
?? ?at kotlinx.coroutines.BuildersKt.runBlocking$default(Unknown Source)
?? ?at com.example.myapplication.testcoroutinue.TestTryCatchKt.testTryCatch12(TestTryCatch.kt:287)
?? ?at com.example.myapplication.testcoroutinue.TestTryCatchKt.main(TestTryCatch.kt:16)
?? ?at com.example.myapplication.testcoroutinue.TestTryCatchKt.main(TestTryCatch.kt)
?
Process finished with exit code 1

可見(jiàn),async 當(dāng)中產(chǎn)生異常,即使不調(diào)用 await() 同樣是會(huì)導(dǎo)致程序崩潰的。

三、SupervisorJob

使用 try-catch 包裹“deferred.await()”,需要配合 SupervisorJob 一起使用。實(shí)現(xiàn)“不調(diào)用 await() 就不會(huì)產(chǎn)生異常而崩潰”。

unBlocking {
        val scope = CoroutineScope(SupervisorJob())
        scope.async {
            delay(100L)
            1 / 0
        }
        delay(500L)
        println("End")
    }

Log
?
End
?
Process finished with exit code 0

使用 SupervisorJob 創(chuàng)建一個(gè) scope 以后,用 scope.async{}啟動(dòng)協(xié)程后,只要不調(diào)用“deferred.await()”,程序就不會(huì)因?yàn)楫惓6罎ⅰ?/p>

  runBlocking {
        val coroutineScope = CoroutineScope(SupervisorJob())
        val deferred = coroutineScope.async {
            delay(100L)
            1 / 0
        }
        try {
            deferred.await()
        } catch (e: Exception) {
            println("Catch:$e")
        }
        delay(500L)
        println("End")
    }

Log
Catch:java.lang.ArithmeticException: / by zero
End
?
Process finished with exit code 0

使用“coroutineScope.async {}”創(chuàng)建了協(xié)程,同時(shí)也用 try-catch 包裹“deferred.await()”,這樣一來(lái),異常就成功地被捕獲了。

public fun SupervisorJob(parent: Job? = null) : CompletableJob 
                    = SupervisorJobImpl(parent)
public interface CompletableJob : Job {
    public fun complete(): Boolean
    public fun completeExceptionally(exception: Throwable): Boolean
}

SupervisorJob() 不是構(gòu)造函數(shù),它只是一個(gè)普通的頂層函數(shù)。這個(gè)方法返回的對(duì)象,是 Job 的子類(lèi)。SupervisorJob 與 Job 最大的區(qū)別就在于,當(dāng)它的子 Job 發(fā)生異常的時(shí)候,其他的子 Job 不會(huì)受到牽連。

對(duì)于普通 Job, 出現(xiàn)異常時(shí)的應(yīng)對(duì)策略是:由于 parentJob 是一個(gè)普通的 Job 對(duì)象,當(dāng) job1 發(fā)生異常之后,它會(huì)導(dǎo)致 parentJob 取消,進(jìn)而導(dǎo)致 job2、job3 也受到牽連。

如果把 parentJob 改為 SupervisorJob,job1 發(fā)生異常的的話,就不會(huì)影響到其他的 Job 了。

注意:靈活使用 SupervisorJob,控制異常傳播的范圍。

四、CoroutineExceptionHandler

runBlocking {
        val coroutineScope = CoroutineScope(coroutineContext)
        coroutineScope.launch {
            async {
                delay(100L)
            }
            launch {
                delay(100L)
                1/0
            }
        }
        delay(1000L)
        println("END")
    }

Exception in thread "main" java.lang.ArithmeticException: / by zero
?? ?at com.example.myapplication.testcoroutinue.TestTryCatchKt$testTryCatch15$1$1$2.invokeSuspend(TestTryCatch.kt:338)
?? ?at kotlin.coroutines.jvm.internal.BaseContinuationImpl.resumeWith(ContinuationImpl.kt:33)
?? ?at kotlinx.coroutines.DispatchedTaskKt.resume(DispatchedTask.kt:234)
?? ?at kotlinx.coroutines.DispatchedTaskKt.dispatch(DispatchedTask.kt:166)
?? ?at kotlinx.coroutines.CancellableContinuationImpl.dispatchResume(CancellableContinuationImpl.kt:397)
?? ?at kotlinx.coroutines.CancellableContinuationImpl.resumeImpl(CancellableContinuationImpl.kt:431)
?? ?at kotlinx.coroutines.CancellableContinuationImpl.resumeImpl$default(CancellableContinuationImpl.kt:420)
?? ?at kotlinx.coroutines.CancellableContinuationImpl.resumeUndispatched(CancellableContinuationImpl.kt:518)
?? ?at kotlinx.coroutines.EventLoopImplBase$DelayedResumeTask.run(EventLoop.common.kt:494)
?? ?at kotlinx.coroutines.EventLoopImplBase.processNextEvent(EventLoop.common.kt:279)
?? ?at kotlinx.coroutines.BlockingCoroutine.joinBlocking(Builders.kt:85)
?? ?at kotlinx.coroutines.BuildersKt__BuildersKt.runBlocking(Builders.kt:59)
?? ?at kotlinx.coroutines.BuildersKt.runBlocking(Unknown Source)
?? ?at kotlinx.coroutines.BuildersKt__BuildersKt.runBlocking$default(Builders.kt:38)
?? ?at kotlinx.coroutines.BuildersKt.runBlocking$default(Unknown Source)
?? ?at com.example.myapplication.testcoroutinue.TestTryCatchKt.testTryCatch15(TestTryCatch.kt:329)
?? ?at com.example.myapplication.testcoroutinue.TestTryCatchKt.main(TestTryCatch.kt:16)
?? ?at com.example.myapplication.testcoroutinue.TestTryCatchKt.main(TestTryCatch.kt)
?
Process finished with exit code 1

使用CoroutineExceptionHandler處理上述代碼中的異常。

  runBlocking {
        val coroutineExceptionHandler = CoroutineExceptionHandler { _, throwable ->
            println("Catch: $throwable")
        }
        val coroutineScope = CoroutineScope(coroutineContext + Job() + coroutineExceptionHandler)
        coroutineScope.launch {
            async {
                delay(100L)
            }
            launch {
                delay(100L)
                1 / 0
            }
        }
        delay(1000L)
        println("END")
    }

Log
Catch: java.lang.ArithmeticException: / by zero
END
?
Process finished with exit code 0

定義了一個(gè) CoroutineExceptionHandler,然后把它傳入了 scope 當(dāng)中,就可以捕獲其中所有的異常了。

注意點(diǎn):在特定場(chǎng)景,為什么 CoroutineExceptionHandler 不起作用?

runBlocking {
        val coroutineExceptionHandler = CoroutineExceptionHandler { _, throwable ->
            println("Catch: $throwable")
        }
        val coroutineScope = CoroutineScope(coroutineContext)
        coroutineScope.launch {
            async {
                delay(100L)
            }
            launch(coroutineExceptionHandler) {
                delay(100L)
                1 / 0
            }
        }
        delay(1000L)
        println("END")
    }

Exception in thread "main" java.lang.ArithmeticException: / by zero
?? ?at com.example.myapplication.testcoroutinue.TestTryCatchKt$testTryCatch17$1$1$2.invokeSuspend(TestTryCatch.kt:383)
?? ?at kotlin.coroutines.jvm.internal.BaseContinuationImpl.resumeWith(ContinuationImpl.kt:33)
?? ?at kotlinx.coroutines.DispatchedTaskKt.resume(DispatchedTask.kt:234)
?? ?at kotlinx.coroutines.DispatchedTaskKt.dispatch(DispatchedTask.kt:166)
?? ?at kotlinx.coroutines.CancellableContinuationImpl.dispatchResume(CancellableContinuationImpl.kt:397)
?? ?at kotlinx.coroutines.CancellableContinuationImpl.resumeImpl(CancellableContinuationImpl.kt:431)
?? ?at kotlinx.coroutines.CancellableContinuationImpl.resumeImpl$default(CancellableContinuationImpl.kt:420)
?? ?at kotlinx.coroutines.CancellableContinuationImpl.resumeUndispatched(CancellableContinuationImpl.kt:518)
?? ?at kotlinx.coroutines.EventLoopImplBase$DelayedResumeTask.run(EventLoop.common.kt:494)
?? ?at kotlinx.coroutines.EventLoopImplBase.processNextEvent(EventLoop.common.kt:279)
?? ?at kotlinx.coroutines.BlockingCoroutine.joinBlocking(Builders.kt:85)
?? ?at kotlinx.coroutines.BuildersKt__BuildersKt.runBlocking(Builders.kt:59)
?? ?at kotlinx.coroutines.BuildersKt.runBlocking(Unknown Source)
?? ?at kotlinx.coroutines.BuildersKt__BuildersKt.runBlocking$default(Builders.kt:38)
?? ?at kotlinx.coroutines.BuildersKt.runBlocking$default(Unknown Source)
?? ?at com.example.myapplication.testcoroutinue.TestTryCatchKt.testTryCatch17(TestTryCatch.kt:371)
?? ?at com.example.myapplication.testcoroutinue.TestTryCatchKt.main(TestTryCatch.kt:16)
?? ?at com.example.myapplication.testcoroutinue.TestTryCatchKt.main(TestTryCatch.kt)
?
Process finished with exit code 1

把自定義的 myExceptionHandler,放到出現(xiàn)異常的 launch 那里傳了進(jìn)去。myExceptionHandler 并不會(huì)起作用,異常不會(huì)被它捕獲。注意:myExceptionHandler 直接定義在發(fā)生異常的位置反而不生效,而定義在最頂層卻可以生效。因?yàn)橹辉陧攲拥膮f(xié)程當(dāng)中才會(huì)起作用。也就是說(shuō),當(dāng)子協(xié)程當(dāng)中出現(xiàn)異常以后,它們都會(huì)統(tǒng)一上報(bào)給頂層的父協(xié)程,然后頂層的父協(xié)程才會(huì)去調(diào)用 CoroutineExceptionHandler,來(lái)處理對(duì)應(yīng)的異常。所以需要記住:使用 CoroutineExceptionHandler 處理復(fù)雜結(jié)構(gòu)的協(xié)程異常,它僅在頂層協(xié)程中起作用。

原文鏈接:https://blog.csdn.net/zhangying1994/article/details/127610104

欄目分類(lèi)
最近更新