Sobes.tech
Middle

Čo sa stane s korutínou, keď nastane výnimka?

sobes.tech AI

Odpoveď od AI

Pri pojave izuzetka unutar korutine, zavisno od tipa izuzetka (i podešavanja dispatcher-a/konteksta), odredjuje se kako će biti obrađen.

  • Nezavisni izuzetak: Ako izuzetak nije uhvaćen unutar korutine, on se propagira nagore kroz hijerarhiju korutina do najbližeg roditeljskog Job (ili CoroutineScope). Ponašanje zavisi od tipa Job:

    • Job: Po podrazumevanom, ako dođe do izuzetka u dečijoj korutini, roditeljski Job se otkazuje, što dovodi do otkazivanja svih ostalih njegovih dečijih korutina. Izuzetak se prenosi nagore.
    • SupervisorJob: Rodi-elski SupervisorJob se ne otkazuje kada dođe do izuzetka u dečijoj korutini. Samo sama korutina u kojoj je došlo do izuzetka se otkazuje. Ovo je korisno kada je potrebno da otkazivanje jedne dečije zadatka ne utiče na ostale.
    • Korenski CoroutineScope: Ako izuzetak dostigne korenski CoroutineScope (npr. GlobalScope ili scope kreiran pomoću CoroutineScope bez Job), on se prenosi u globalni obradač izuzetaka CoroutineExceptionHandler. Po podrazumevanom, ako nema registrovanog obradača, izuzetak se loguje u System.err.
  • Uhvaćen izuzetak: Ako je izuzetak uhvaćen pomoću try-catch bloka unutar korutine, on se obrađuje lokalno, i korutina nastavlja sa izvršavanjem nakon bloka catch, ako je to moguće. Izuzetak se ne prenosi nagore.

  • Izuzeci povezani sa otkazivanjem (npr. CancellationException): Ovi izuzeci su posebni. Oni se koriste za mehanizam otkazivanja korutina i obično se ignorišu većinom obrađivača izuzetaka po podrazumevanom. Oni ne dovode do fatalnog pada roditeljskog Job po podrazumevanom.

  • Izuzeci u async: Korutina pokrenuta pomoću async postavlja izuzetak u svoj Deferred. Izuzetak se prenosi samo pri pozivu .await() na tom Deferred. Do tada je izuzetak "skriven".

import kotlinx.coroutines.*

fun main() = runBlocking {
    val scope = CoroutineScope(SupervisorJob())

    scope.launch {
        try {
            println("Korutina 1 počela")
            delay(100)
            throw RuntimeException("Nešto je pošlo po zlu u Korutini 1")
        } catch (e: Exception) {
            println("Uhvaćen izuzetak u Korutini 1: ${e.message}")
        }
    }

    scope.launch {
        println("Korutina 2 počela")
        delay(500)
        println("Korutina 2 završila")
    }

    delay(1000) // Čekamo da vidimo ispis
    scope.cancel() // Otkažemo scope
}

U ovom primeru, izuzetak u Korutini 1 je uhvaćen, i Korutina 2 nastavlja sa izvršavanjem, jer je korišćen SupervisorJob. Ako bi bio korišćen običan Job, izuzetak u Korutini 1 bi doveo do otkazivanja Korutine 2.