Sobes.tech
Middle

Ποιους τρόπους διαχείρισης σφαλμάτων σε κορουτίνες γνωρίζετε;

sobes.tech AI

Απάντηση από AI

  • Χρήση των μπλοκ try...catch. Τυπικός τρόπος διαχείρισης εξαιρέσεων. Λειτουργεί μέσα σε μια coroutine.

    // Εφαρμογή try-catch
    suspend fun fetchData(): String {
        return try {
            // Ενέργεια που μπορεί να ρίξει εξαίρεση
            throw Exception("Σφάλμα φόρτωσης δεδομένων")
            "Τα δεδομένα φορτώθηκαν επιτυχώς"
        } catch (e: Exception) {
            "Σφάλμα: ${e.message}"
        }
    }
    

    Το try...catch δεν είναι κατάλληλο για τη διαχείριση ανεπεξέργαστων εξαιρέσεων που ρίχνονται από παιδικές coroutine που τρέχουν σε διαφορετικό CoroutineScope.

  • CoroutineExceptionHandler. Πιάνει μη επεξεργασμένες εξαιρέσεις που ρίχνονται από coroutine, που ξεκινούν σε αυτό το CoroutineScope ή στους παιδικούς CoroutineScope του.

    // CoroutineExceptionHandler
    val handler = CoroutineExceptionHandler { _, exception ->
        println("Πιασμένη εξαίρεση: $exception")
    }
    
    // Εφαρμογή του CoroutineExceptionHandler
    GlobalScope.launch(handler) {
        // Coroutine που μπορεί να ρίξει εξαίρεση
        throw Exception("Σφάλμα στη coroutine")
    }
    

    Το CoroutineExceptionHandler ενεργοποιείται μόνο για εξαιρέσεις που δεν διαχειρίζονται από τον μηχανισμό δομημένου ανταγωνισμού.

  • SupervisorJob και supervisorScope. Σε αντίθεση με ένα συνηθισμένο Job, όταν μια παιδική coroutine με σφάλμα προκαλεί ακύρωση του γονικού Job, το SupervisorJob δεν ακυρώνει τον γονικό Job. Το supervisorScope δημιουργεί ένα CoroutineScope με SupervisorJob.

    // Χρήση του supervisorScope
    suspend fun loadMultipleData() = supervisorScope {
        val data1 = async {
            // Μπορεί να ρίξει εξαίρεση
            throw Exception("Σφάλμα στα δεδομένα 1")
            "Δεδομένα 1"
        }
        val data2 = async {
            "Δεδομένα 2"
        }
    
        // Διαχείριση εξαίρεσης για συγκεκριμένο async
        try {
            println("Αποτέλεσμα 1: ${data1.await()}")
        } catch (e: Exception) {
            println("Σφάλμα κατά τη φόρτωση δεδομένων 1: ${e.message}")
        }
        println("Αποτέλεσμα 2: ${data2.await()}")
    }
    

    Χρησιμοποιείται για ανεξάρτητες εργασίες παιδιών, όπου το σφάλμα ενός δεν πρέπει να επηρεάζει τα άλλα. Δεν αντικαθιστά το try...catch ή το CoroutineExceptionHandler, αλλά αλλάζει τη συμπεριφορά διάδοσης εξαιρέσεων.

  • Διάδοση εξαιρέσεων στη δομημένη ανταγωνιστικότητα. Από προεπιλογή, μια εξαίρεση σε παιδική coroutine ακυρώνει την γονική coroutine και όλους τους αδελφούς της.

    // Παράδειγμα διάδοσης εξαίρεσης
    runBlocking {
        val job = launch {
            launch { // Παιδική coroutine 1
                delay(100)
                throw Exception("Σφάλμα στην παιδική 1")
            }
            launch { // Παιδική coroutine 2
                delay(200)
                println("Παιδική 2 ολοκληρώθηκε")
            }
        }
        try {
            job.join()
        } catch (e: Exception) {
            println("Πιάστηκε εξαίρεση στη γονική: $e")
        }
    }
    

    Αυτή είναι η βασική συμπεριφορά της δομημένης ανταγωνιστικότητας, που βοηθά στην αποφυγή διαρροών πόρων και καταστάσεων.

  • Χρήση του async με await(). Οι εξαιρέσεις που ρίχνονται στο async δεν διαχέονται αυτόματα. Αποθηκεύονται μέσα στο Deferred και ρίχνονται μόνο κατά την κλήση του await().

    // Διαχείριση εξαιρέσεων με async/await
    suspend fun safeAsyncCall() = coroutineScope {
        val deferred = async {
            throw Exception("Σφάλμα στο async")
            "Αποτέλεσμα async"
        }
    
        try {
            val result = deferred.await()
            println("Αποτέλεσμα: $result")
        } catch (e: Exception) {
            println("Πιάστηκε εξαίρεση από το async: ${e.message}")
        }
    }
    

    Αυτό επιτρέπει την επιλεκτική διαχείριση σφαλμάτων για κάθε ασύγχρονη εργασία.

Τρόπος Σκοπός Διαχειρίζεται uncaught; Αλλάζει τη διάδοση;
try...catch Διαχείριση εξαιρέσεων μέσα στη τρέχουσα coroutine Όχι Όχι
CoroutineExceptionHandler Πιάσιμο μη διαχειριζόμενων εξαιρέσεων σε Scope Ναι Όχι
SupervisorJob/Scope Αλλαγή συμπεριφοράς διάδοσης εξαιρέσεων Όχι Ναι
Δομημένη ανταγωνιστικότητα Αυτόματη ακύρωση σε περίπτωση σφάλματος Ναι Ναι
async + await() Απομακρυσμένη διάδοση εξαιρέσεων Όχι Ναι (μέχρι το await)