What methods of error handling in coroutines do you know?
sobes.tech AI
Answer from AI
-
Usage of
try...catchblocks. Standard way of exception handling. Works inside a coroutine.// Using try-catch suspend fun fetchData(): String { return try { // Operation that may throw an exception throw Exception("Data loading error") "Data loaded successfully" } catch (e: Exception) { "Error: ${e.message}" } }try...catchis not suitable for handling uncaught exceptions thrown from child coroutines launched in anotherCoroutineScope. -
CoroutineExceptionHandler. Catches unhandled exceptions thrown by coroutines launched in thisCoroutineScopeor its childCoroutineScopes.// CoroutineExceptionHandler val handler = CoroutineExceptionHandler { _, exception -> println("Caught exception: $exception") } // Applying CoroutineExceptionHandler GlobalScope.launch(handler) { // Coroutine that may throw an exception throw Exception("Error in coroutine") }CoroutineExceptionHandlertriggers only for exceptions not handled by structured concurrency mechanisms. -
SupervisorJobandsupervisorScope. Unlike a regularJob, when a child coroutine with an error causes the parentJobto cancel,SupervisorJobdoes not cancel the parentJobon a child's error.supervisorScopecreates aCoroutineScopewith aSupervisorJob.// Using supervisorScope suspend fun loadMultipleData() = supervisorScope { val data1 = async { // May throw an exception throw Exception("Error in data 1") "Data 1" } val data2 = async { "Data 2" } // Can handle exception for specific async try { println("Result 1: ${data1.await()}") } catch (e: Exception) { println("Error loading data 1: ${e.message}") } println("Result 2: ${data2.await()}") }Used for independent child tasks where one error should not affect others. Does not replace
try...catchorCoroutineExceptionHandler, but rather changes exception propagation behavior. -
Exception propagation in structured concurrency. By default, an exception in a child coroutine cancels the parent coroutine and all its siblings.
// Example of exception propagation runBlocking { val job = launch { launch { // Child coroutine 1 delay(100) throw Exception("Error in child 1") } launch { // Child coroutine 2 delay(200) println("Child 2 completed") } } try { job.join() } catch (e: Exception) { println("Exception caught in parent: $e") } }This is the default behavior of structured concurrency, helping to avoid resource leaks and inconsistent states.
-
Using
asyncwithawait(). Exceptions thrown inasyncare not propagated automatically. They are stored insideDeferredand thrown only when callingawait().// Handling exceptions with async/await suspend fun safeAsyncCall() = coroutineScope { val deferred = async { throw Exception("Error in async") "Async result" } try { val result = deferred.await() println("Result: $result") } catch (e: Exception) { println("Caught exception from async: ${e.message}") } }This allows selective error handling for each asynchronous task.
| Method | Purpose | Handles uncaught? | Changes propagation? |
|---|---|---|---|
try...catch |
Handles exceptions within the current coroutine | No | No |
CoroutineExceptionHandler |
Catches unhandled exceptions in Scope | Yes | No |
SupervisorJob/Scope |
Changes exception propagation behavior | No | Yes |
| Structured concurrency | Automatic cancellation on error | Yes | Yes |
async + await() |
Deferred exception propagation | No | Yes (before await) |