Sobes.tech
Middle

Koje načine za obradu grešaka u korutinama poznajete?

sobes.tech АИ

Одговор од АИ

  • Korišćenje try...catch blokova. Standardan način za obradu izuzetaka. Radi unutar korutine.

    // Korišćenje try-catch
    suspend fun fetchData(): String {
        return try {
            // Operacija koja može da baci izuzetak
            throw Exception("Greška pri učitavanju podataka")
            "Podaci uspešno učitani"
        } catch (e: Exception) {
            "Greška: ${e.message}"
        }
    }
    

    try...catch nije pogodan za obradu neuhvaćenih izuzetaka, bačenih od strane podkora, pokrenutih u drugom CoroutineScope.

  • CoroutineExceptionHandler. Hvata neobrađene izuzetke, bačene od strane korutina koje su pokrenute u ovom CoroutineScope ili njegovim podkora.

    // CoroutineExceptionHandler
    val handler = CoroutineExceptionHandler { _, exception ->
        println("Uhvaćen izuzetak: $exception")
    }
    
    // Korišćenje CoroutineExceptionHandler
    GlobalScope.launch(handler) {
        // Korutina koja može da baci izuzetak
        throw Exception("Greška u korutini")
    }
    

    CoroutineExceptionHandler se aktivira samo za izuzetke koji nisu obrađeni mehanizmom strukturirane konkurencije.

  • SupervisorJob i supervisorScope. Za razliku od običnog Job, kada podkora sa greškom dovodi do otkazivanja roditeljskog Job, SupervisorJob ne otkazuje roditeljski Job pri grešci podkore. supervisorScope kreira CoroutineScope sa SupervisorJob.

    // Korišćenje supervisorScope
    suspend fun loadMultipleData() = supervisorScope {
        val data1 = async {
            // Može da baci izuzetak
            throw Exception("Greška u podacima 1")
            "Podaci 1"
        }
        val data2 = async {
            "Podaci 2"
        }
    
        // Može da obradi izuzetak za konkretnu async
        try {
            println("Rezultat 1: ${data1.await()}")
        } catch (e: Exception) {
            println("Greška pri učitavanju podataka 1: ${e.message}")
        }
        println("Rezultat 2: ${data2.await()}")
    }
    

    Koristi se za nezavisne podzadatke, gde greška jednog ne bi trebalo da utiče na ostale. Ne zamenjuje try...catch ili CoroutineExceptionHandler, već menja ponašanje širenja izuzetaka.

  • Širenje izuzetaka u strukturiranoj konkurenciji. Po default-u, izuzetak u podkori otkazuje roditeljsku korutinu i sve njene srodnike.

    // Primer širenja izuzetka
    runBlocking {
        val job = launch {
            launch { // Podkora 1
                delay(100)
                throw Exception("Greška u podkori 1")
            }
            launch { // Podkora 2
                delay(200)
                println("Podkora 2 završila")
            }
        }
        try {
            job.join()
        } catch (e: Exception) {
            println("Uhvaćen izuzetak u roditelju: $e")
        }
    }
    

    Ovo je osnovno ponašanje strukturirane konkurencije, koje pomaže da se izbegnu curenja resursa i stanja.

  • Korišćenje async sa await(). Izuzeci, bačeni u async, ne se automatski šire. Oni se čuvaju unutar Deferred i bacaju se samo pri pozivu await().

    // Obrada izuzetaka sa async/await
    suspend fun safeAsyncCall() = coroutineScope {
        val deferred = async {
            throw Exception("Greška u async")
            "Rezultat async"
        }
    
        try {
            val result = deferred.await()
            println("Rezultat: $result")
        } catch (e: Exception) {
            println("Uhvaćen izuzetak iz async: ${e.message}")
        }
    }
    

    Ovo omogućava selektivnu obradu grešaka za svaku asinhronu zadatak.

Način Namenjen za Obradjuje neuhvaćene? Menja širenje?
try...catch Obrada izuzetaka unutar trenutne korutine Ne Ne
CoroutineExceptionHandler Hvata neobrađene izuzetke u Scope Da Ne
SupervisorJob/Scope Promena ponašanja širenja izuzetaka Ne Da
Struktuisana konkurencija Automatsko otkazivanje pri grešci Da Da
async + await() Odloženo širenje izuzetka Ne Da (do await)