Sobes.tech
Middle

What methods of error handling in coroutines do you know?

sobes.tech AI

Answer from AI

  • Usage of try...catch blocks. 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...catch is not suitable for handling uncaught exceptions thrown from child coroutines launched in another CoroutineScope.

  • CoroutineExceptionHandler. Catches unhandled exceptions thrown by coroutines launched in this CoroutineScope or its child CoroutineScopes.

    // 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")
    }
    

    CoroutineExceptionHandler triggers only for exceptions not handled by structured concurrency mechanisms.

  • SupervisorJob and supervisorScope. Unlike a regular Job, when a child coroutine with an error causes the parent Job to cancel, SupervisorJob does not cancel the parent Job on a child's error. supervisorScope creates a CoroutineScope with a SupervisorJob.

    // 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...catch or CoroutineExceptionHandler, 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 async with await(). Exceptions thrown in async are not propagated automatically. They are stored inside Deferred and thrown only when calling await().

    // 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)
What methods of error handling in coroutines do you… - sobes.tech