Τι συμβαίνει με μια coroutine όταν προκύψει μια εξαίρεση;
sobes.tech AI
Απάντηση από AI
Όταν προκύψει μια εξαίρεση μέσα σε μια coroutine, η εξάρτηση από τον τύπο της εξαίρεσης (και τις ρυθμίσεις dispatcher/περιβάλλοντος) καθορίζει πώς θα αντιμετωπιστεί.
-
Μη ελεγχόμενη εξαίρεση: Αν η εξαίρεση δεν πιαστεί μέσα στη coroutine, διαχέεται προς τα πάνω στην ιεραρχία των coroutines μέχρι το πλησιέστερο
JobήCoroutineScope. Η συμπεριφορά εξαρτάται από τον τύπο τουJob:Job: Από προεπιλογή, όταν προκύψει μια εξαίρεση σε μια παιδική coroutine, το γονικόJobακυρώνεται, οδηγώντας στην ακύρωση όλων των άλλων παιδικών coroutines του. Η εξαίρεση διαχέεται προς τα πάνω.SupervisorJob: Το γονικόSupervisorJobδεν ακυρώνεται όταν προκύψει εξαίρεση σε μια παιδική coroutine. Μόνο η coroutine στην οποία συνέβη η εξαίρεση ακυρώνεται. Αυτό είναι χρήσιμο όταν θέλεις η ακύρωση μιας παιδικής εργασίας να μην επηρεάζει τις άλλες.CoroutineScopeριζικό: Αν η εξαίρεση φτάσει στο ριζικόCoroutineScope(π.χ.GlobalScopeή ένα scope που δημιουργήθηκε μεCoroutineScopeχωρίςJob), μεταβιβάζεται στον παγκόσμιο χειριστή εξαιρέσεωνCoroutineExceptionHandler. Από προεπιλογή, αν δεν υπάρχει καταχωρημένος χειριστής, η εξαίρεση καταγράφεται στοSystem.err.
-
Πιασμένη εξαίρεση: Αν η εξαίρεση πιαστεί με ένα μπλοκ
try-catchμέσα στη coroutine, αντιμετωπίζεται τοπικά και η coroutine συνεχίζει την εκτέλεση μετά το μπλοκcatch, αν αυτό είναι δυνατό. Η εξαίρεση δεν διαχέεται προς τα πάνω. -
Εξαιρέσεις που σχετίζονται με την ακύρωση (π.χ.
CancellationException): Αυτές οι εξαιρέσεις είναι ειδικές. Χρησιμοποιούνται για τον μηχανισμό ακύρωσης των coroutines και γενικά αγνοούνται από τους περισσότερους χειριστές εξαιρέσεων από προεπιλογή. Δεν προκαλούν καταστροφική αποτυχία του γονικούJobαπό προεπιλογή. -
Εξαιρέσεις στο
async: Η coroutine που ξεκινά μεasyncτοποθετεί την εξαίρεση στο δικό τηςDeferred. Η εξαίρεση διαχέεται μόνο όταν καλέσεις.await()σε αυτό τοDeferred. Μέχρι τότε, η εξαίρεση είναι "κρυμμένη".
import kotlinx.coroutines.*
fun main() = runBlocking {
val scope = CoroutineScope(SupervisorJob())
scope.launch {
try {
println("Η coroutine 1 ξεκίνησε")
delay(100)
throw RuntimeException("Κάτι πήγε στραβά στην coroutine 1")
} catch (e: Exception) {
println("Πιασμένη εξαίρεση στην coroutine 1: ${e.message}")
}
}
scope.launch {
println("Η coroutine 2 ξεκίνησε")
delay(500)
println("Η coroutine 2 τελείωσε")
}
delay(1000) // Περιμένουμε να δούμε την έξοδο
scope.cancel() // Ακυρώνουμε το scope
}
Σε αυτό το παράδειγμα, η εξαίρεση στην Coroutine 1 πιάστηκε και η Coroutine 2 συνεχίζει την εκτέλεση επειδή χρησιμοποιείται SupervisorJob. Αν χρησιμοποιούνταν ένα κανονικό Job, η εξαίρεση στην Coroutine 1 θα οδηγούσε στην ακύρωση της Coroutine 2.