Exception handling in coroutines in Kotlin - Time & Space Complexity
When using coroutines, handling exceptions can affect how long your program runs.
We want to see how exception handling changes the work done as input grows.
Analyze the time complexity of the following code snippet.
import kotlinx.coroutines.*
fun main() = runBlocking {
val jobs = List(1000) { i ->
launch {
try {
if (i == 500) throw Exception("Error at 500")
delay(10)
} catch (e: Exception) {
println(e.message)
}
}
}
jobs.forEach { it.join() }
}
This code launches 1000 coroutines, each delaying briefly, but one throws and catches an exception.
Identify the loops, recursion, array traversals that repeat.
- Primary operation: Launching and running 1000 coroutines with delay and exception handling.
- How many times: The coroutine block runs once per item in the list, so 1000 times.
Each coroutine runs independently, so total work grows with the number of coroutines.
| Input Size (n) | Approx. Operations |
|---|---|
| 10 | About 10 coroutine launches and delays |
| 100 | About 100 coroutine launches and delays |
| 1000 | About 1000 coroutine launches and delays |
Pattern observation: The work grows directly with the number of coroutines launched.
Time Complexity: O(n)
This means the total time grows linearly as you add more coroutines, even with exception handling.
[X] Wrong: "Exception handling inside coroutines makes the time grow much faster than the number of coroutines."
[OK] Correct: Exception handling adds some overhead but does not multiply the work; each coroutine still runs once.
Understanding how exceptions affect coroutine performance shows you can write reliable and efficient asynchronous code.
"What if we replaced the try-catch inside each coroutine with a single CoroutineExceptionHandler for all coroutines? How would the time complexity change?"
Practice
launch?Solution
Step 1: Understand coroutine exception handling basics
Exceptions insidelaunchcoroutines are caught bytry-catchblocks within the coroutine code itself.Step 2: Identify correct method to catch exceptions
Thecatchmethod does not exist on coroutine builders, andfinallyoutside coroutine does not catch coroutine exceptions.Final Answer:
Use try-catch block inside the coroutine code -> Option AQuick Check:
try-catch inside coroutine = correct way [OK]
- Thinking catch method exists on coroutine builders
- Using finally block outside coroutine to catch exceptions
- Assuming exceptions cannot be caught in coroutines
CoroutineExceptionHandler in Kotlin?Solution
Step 1: Recall CoroutineExceptionHandler signature
It takes a lambda with two parameters:contextandexception.Step 2: Match correct syntax
val handler = CoroutineExceptionHandler { context, exception -> println(exception) } correctly uses the two parameters in the lambda. Other options miss parameters or have wrong syntax.Final Answer:
val handler = CoroutineExceptionHandler { context, exception -> println(exception) } -> Option DQuick Check:
CoroutineExceptionHandler requires (context, exception) lambda [OK]
- Omitting context parameter in lambda
- Passing parameters incorrectly
- Using invalid constructor syntax
import kotlinx.coroutines.*
fun main() = runBlocking {
val handler = CoroutineExceptionHandler { _, exception ->
println("Caught: ${exception.message}")
}
val job = launch(handler) {
throw IllegalArgumentException("Invalid argument")
}
job.join()
println("Done")
}Solution
Step 1: Understand CoroutineExceptionHandler usage
The handler catches exceptions thrown inside thelaunchcoroutine and prints the message.Step 2: Trace program output
The exception message "Invalid argument" is printed by the handler, then "Done" is printed afterjob.join().Final Answer:
Caught: Invalid argument Done -> Option AQuick Check:
Exception caught by handler, then Done printed [OK]
- Expecting uncaught exception crash
- Missing that handler catches exception
- Ignoring job.join() effect
import kotlinx.coroutines.*
fun main() = runBlocking {
val handler = CoroutineExceptionHandler { _, exception ->
println("Error: ${exception.message}")
}
val job = async(handler) {
throw RuntimeException("Failure")
}
job.await()
}Solution
Step 1: Understand exception handling difference between launch and async
Exceptions inasyncare propagated via the deferred result and must be caught bytry-catchonawait().Step 2: Analyze why CoroutineExceptionHandler fails here
CoroutineExceptionHandler does not catch exceptions fromasynccoroutines because they are deferred untilawait().Final Answer:
CoroutineExceptionHandler does not catch exceptions from async coroutines -> Option CQuick Check:
async exceptions need try-catch on await() [OK]
- Expecting CoroutineExceptionHandler to catch async exceptions
- Ignoring need for try-catch on await()
- Misunderstanding handler lambda parameters
launch coroutines in a Kotlin app and log errors without stopping other coroutines. Which approach is best?Solution
Step 1: Understand exception handling for multiple launch coroutines
Using a sharedCoroutineExceptionHandleron the parent scope catches exceptions from all childlaunchcoroutines without cancelling siblings.Step 2: Evaluate other options
Wrapping each coroutine in try-catch is verbose and error-prone; async with await is for deferred results; SupervisorJob alone does not handle exceptions or logging.Final Answer:
Attach a shared CoroutineExceptionHandler to the parent scope and launch coroutines within it -> Option BQuick Check:
Shared handler on parent scope manages launch exceptions [OK]
- Ignoring shared handler benefits
- Using async instead of launch for fire-and-forget
- Not handling exceptions leads to crashes
Ready to prove it?
Pass the test and this pattern moves unknown
