Kotlin Academy · Lekcja

Ponowne rzucanie wyjątków i ich łańcuchowanie

Ponownie rzucaj wybrane wyjątki i opakowuj błędy niższego poziomu, zachowując ich przyczynę.

Lekcja 4 z 413 kroki

Ponowne rzucanie wyjątków i ich łańcuchowanie to bezpłatna lekcja Kotlin Academy na CoddyKit. To lekcja 4 z 4. Możesz przeczytać całą lekcję poniżej za darmo — a potem ćwiczyć ją interaktywnie w przeglądarce z wbudowanym edytorem kodu i tutorem AI dostępnym 24/7. To część ścieżki edukacyjnej Kotlin Academy, a Twój postęp synchronizuje się między webem a aplikacją CoddyKit. Kurs Kotlin Academy zawiera 4 lekcji w sumie.

Ponowne zgłaszanie i opakowywanie

Czasami przechwytujesz wyjątek tylko po to, aby go zarejestrować, opakować lub przekształcić, zanim pozwolisz, aby propagował się bardziej szczegółowy wyjątek. Kotlin ułatwia stosowanie takiego idiomatycznego podejścia.

Ponowne zgłoszenie bez opakowywania

Aby ponownie zgłosić wyjątek, po prostu użyj ponownie throw e — propagacja będzie kontynuowana do następnego programu obsługi.

fun main() {
    try {
        try { "x".toInt() }
        catch (e: NumberFormatException) {
            println("logging: ${e.message}")
            throw e // re-throw original
        }
    } catch (e: NumberFormatException) {
        println("outer caught: ${e.message}")
    }
}

Opakowywanie za pomocą własnego wyjątku

Podczas tworzenia nowego wyjątku przekaż pierwotny wyjątek jako cause, aby zachować łańcuch przyczyn.

class ParseException(msg: String, cause: Throwable) : RuntimeException(msg, cause)
fun main() {
    try {
        try { "xyz".toInt() }
        catch (e: NumberFormatException) {
            throw ParseException("could not parse user input", e)
        }
    } catch (e: ParseException) {
        println("got: ${e.message}")
        println("cause: ${e.cause?.message}")
    }
}

Sprawdzanie łańcucha przyczyn

Właściwość cause odwołuje się do poprzedniego wyjątku. Przejdź po tym łańcuchu, aby wyświetlić pełną przyczynę źródłową.

fun main() {
    val e = RuntimeException("top",
        RuntimeException("middle",
            RuntimeException("root")))
    var current: Throwable? = e
    while (current != null) {
        println(current.message)
        current = current.cause
    }
}

Wybiórcze ponowne zgłaszanie

Przechwyć szeroki typ, a następnie zgłoś wyjątek ponownie, jeśli NIE odpowiada oczekiwanemu przypadkowi.

fun parseRequired(s: String): Int {
    try {
        return s.toInt()
    } catch (e: NumberFormatException) {
        if (s.isBlank()) return 0
        throw e // unexpected — let it propagate
    }
}
fun main() {
    println(parseRequired("42"))
    println(parseRequired(""))
    // parseRequired("abc") // throws
}

Dodawanie kontekstu

Owiń wyjątek wyjątkiem domenowym, aby dodać kontekst, którego brakowało w oryginale (dane wejściowe, identyfikator żądania itp.).

class UploadError(msg: String, cause: Throwable) : RuntimeException(msg, cause)
fun upload(file: String) {
    try { throw RuntimeException("disk full") }
    catch (e: Throwable) { throw UploadError("uploading $file failed", e) }
}
fun main() {
    try { upload("photo.jpg") }
    catch (e: UploadError) { println("${e.message} <- ${e.cause?.message}") }
}

Nie trać śladu stosu

Podczas opakowywania zawsze przekaż oryginalny wyjątek jako cause — nigdy nie twórz po prostu nowego wyjątku z tym samym komunikatem, ale bez przyczyny. Ślad stosu jest niezbędny podczas debugowania.

class Wrapped(m: String, cause: Throwable) : RuntimeException(m, cause)
fun main() {
    try {
        try { error("inner") }
        catch (e: Throwable) { throw Wrapped("outer", e) }
    } catch (e: Wrapped) {
        println("message: ${e.message}")
        println("cause: ${e.cause?.message}")
    }
}

Ponowne zgłaszanie bez opakowywania

Jeśli potrzebujesz tylko rejestrowania, po wywołaniu funkcji rejestrującej użyj po prostu throw e — opakowywanie nie jest konieczne.

fun risky() {
    try { throw IllegalStateException("oops") }
    catch (e: IllegalStateException) {
        println("Logging before rethrow: ${e.message}")
        throw e
    }
}
fun main() {
    try { risky() }
    catch (e: IllegalStateException) { println("outer: ${e.message}") }
}

finally do sprzątania podczas ponownego zgłaszania

Używaj finally do sprzątania zasobów, nawet gdy ponownie zgłaszasz wyjątek.

fun process() {
    try {
        throw RuntimeException("failure")
    } finally {
        println("cleanup ran")
    }
}
fun main() {
    try { process() }
    catch (e: RuntimeException) { println("caught: ${e.message}") }
}

Wyjątki stłumione

Jeśli sam blok finally zgłosi wyjątek, pierwotny wyjątek jest domyślnie tłumiony. Użyj addSuppressed, aby zachować oba wyjątki.

fun main() {
    val primary = RuntimeException("primary")
    val secondary = RuntimeException("from cleanup")
    primary.addSuppressed(secondary)
    println(primary.suppressed.joinToString { it.message ?: "?" })
}

Antywzorzec: przechwycenie, a następnie zgłoszenie innego wyjątku

Przechwycenie jednego wyjątku i zgłoszenie niezwiązanego z nim nowego wyjątku (bez przyczyny) niszczy informacje pomocne w debugowaniu. Zawsze należy przekazywać cause.

// BAD
// catch (e: IOException) { throw RuntimeException("error") }
// GOOD
// catch (e: IOException) { throw RuntimeException("error reading config", e) }
fun main() { println("Pass cause when re-throwing!") }

Szybkie sprawdzenie

Co należy zrobić, opakowując wyjątek w nowy wyjątek, aby zachować oryginalny ślad stosu?

Podsumowanie

Aby ponownie zgłosić wyjątek, użyj throw e. Aby go opakować, zgłoś nowy wyjątek z cause = e. Zawsze zachowuj łańcuch przyczyn — nigdy nie twórz opakowania bez przyczyny. Do sprzątania używaj finally, a gdy samo sprzątanie zakończy się błędem, używaj addSuppressed.

Bezpłatny start

Ucz się Kotlin dzięki korepetycjom AI — za darmo

Pisz i uruchamiaj kod w przeglądarce, otrzymuj natychmiastową pomoc od korepetytora AI dostępnego 24/7 i kontynuuj naukę w sieci lub w aplikacji.

Kursy
51
Lekcje
203

Często zadawane pytania

Czy lekcja „Ponowne rzucanie wyjątków i ich łańcuchowanie” jest bezpłatna?

Tak — pełny tekst „Ponowne rzucanie wyjątków i ich łańcuchowanie” jest dostępny za darmo tutaj w sieci. Aby ćwiczyć ją interaktywnie (wbudowany edytor kodu i tutor AI dostępny 24/7) i odblokować resztę kursu Kotlin Academy, przejdź na CoddyKit PRO. Kurs Kotlin Academy zawiera 4 lekcji w sumie.

Co nauczysz się w „Ponowne rzucanie wyjątków i ich łańcuchowanie”?

Ponownie rzucaj wybrane wyjątki i opakowuj błędy niższego poziomu, zachowując ich przyczynę. Ćwiczysz Kotlin Academy z praktycznym kodem, który uruchamiasz bezpośrednio w przeglądarce, a tutor AI dostępny 24/7 odpowiada na Twoje pytania podczas pracy nad lekcją.

Czy potrzebuję doświadczenia, aby zacząć Kotlin Academy?

Nie wymagamy żadnego doświadczenia. Kotlin Academy w CoddyKit jest strukturyzowany dla początkujących i zaawansowanych użytkowników, więc możesz zacząć tutaj lub od początku i uczyć się w swoim tempie. To lekcja 4 z 4.

Ile czasu zajmuje lekcja „Ponowne rzucanie wyjątków i ich łańcuchowanie”?

Większość lekcji CoddyKit trwa około 5–10 minut. Każda lekcja to mały, interaktywny krok, dzięki czemu robisz systematyczne postępy i zawsze wracasz dokładnie do tego samego miejsca — na webie i w aplikacji.

Czy mogę pisać i uruchamiać kod w tej lekcji Kotlin Academy?

Tak. Każda lekcja Kotlin Academy zawiera wbudowany edytor kodu, więc piszesz i uruchamiasz prawdziwy kod bezpośrednio w przeglądarce i od razu otrzymujesz sprzężenie zwrotne od AI — bez konfiguracji na komputerze.

Wszystkie lekcje w tym kursie

  1. try/catch/finally jako wyrażenie
  2. Tworzenie własnych klas wyjątków
  3. runCatching i Result
  4. Ponowne rzucanie wyjątków i ich łańcuchowanie
← Powrót do Kotlin Academy