As the title says, why do suspending functions throw exceptions in finally?
With regular functions, the finally-block executes all of them:
import kotlinx.coroutines.*
fun main() {
val handler = CoroutineExceptionHandler { _, exception ->
println("Caught $exception")
}
val job = GlobalScope.launch(handler) {
launch {
// the first child
try {
println("inside try")
delay(1000)
} finally {
println("Children are cancelled, but exception is not handled until all children terminate")
Thread.sleep(1000)
println("thread.sleep executed")
//foo()
println("The first child finished its non cancellable block")
}
}
launch {
// the second child
delay(10)
println("Second child throws an exception")
throw ArithmeticException()
}
}
Thread.sleep(1000000)
println("complete")
}
Here, for example, when I do Thread.sleep(1000) it prints:
"The first child finished its non cancellable block"
but if I change that line to delay(1000), it does not.
From my understanding, in a finally-block, the exception, if it exists, is thrown after executing the entire block.
But in this case, delay causes this exception to be thrown early.
On the other hand, Thread.sleep does not.
Can someone help explain?
Suspending functions in Kotlin work differently than blocking function. When you cancel a
Job, at the first suspension after the cancellation the execution will be stopped, even if you are in afinallyblock. If you useThread.sleep(1000)instead ofdelay(1000)in yourfinallyblock, there are no suspensions taking place, becauseThread.sleep()is blocking, not suspending, so your wholefinallyblock gets executed.Note that using blocking functions inside of suspending functions is an anti-pattern and should be avoided!!
To achieve this desired behavior without using blocking functions, use
withContext(NonCancellable) {...}as described here.Your example code should look like this:
The output: