programowanieProgramista Backend

Jak działa obsługa wyjątków (exception handling) w Kotlin? Opisz niuanse, różnice względem Java, obsługę wyjątków checked/unchecked, 'try', 'catch', 'finally', propagację i najlepsze praktyki. Podaj przykład.

Zdaj rozmowy kwalifikacyjne z asystentem AI Hintsage

Odpowiedź.

Kotlin realizuje obsługę wyjątków (exception handling) podobnie jak Java, ale z ważnymi różnicami. W Kotlin używane są znane konstrukcje try, catch i finally, jednak zasadnicza różnica polega na tym, że w Kotlin brak jest wyjątków checked. Oznacza to, że wszystkie wyjątki (błędy w czasie wykonywania) są traktowane jako unchecked — nie trzeba ich deklarować w sygnaturze funkcji ani jawnie przechwytywać.

Główne punkty:

  • try/catch/finally pozwalają przechwytywać i obsługiwać wyjątki. Blok finally jest wykonywany zawsze, nawet jeśli wystąpi wyjątek.
  • Różnica w porównaniu do Java: w Kotlin wszystkie wyjątki są unchecked. Ułatwia to składnię, ale wymaga ostrożnego podejścia do obsługi błędów.
  • Kotlin wspiera "return value" bloku try, tj. try można używać jako wyrażenia, zwracając wynik.
  • Nowe idiomy: zaleca się unikanie używania try/catch do kontroli przepływu — stosuj je tylko w rzeczywiście wyjątkowych sytuacjach.
fun parseIntOrNull(str: String): Int? = try { str.toInt() } catch (e: NumberFormatException) { null }

Najlepsze praktyki:

  • Nie używaj do zarządzania logiką (kontroli przepływu).
  • Używaj zarządzania zasobami (resource management) z pomocą use do automatycznego zamykania (np. plików).
  • Nie ignoruj wyjątków pustym catch.

Pytanie z haczykiem.

Czy w Kotlin należy określać w sygnaturze funkcji, jakie wyjątki może rzucać (jak w Java — przez throws)?

Prawidłowa odpowiedź: Nie, w Kotlin brak jest mechanizmu checked exceptions. Wszystkie wyjątki są unchecked. Nie istnieje składnia throws w sygnaturze funkcji (wyjątek — adnotacja @Throws dla kompatybilności z Java, tylko do interop).

Przykłady rzeczywistych błędów z powodu braku znajomości subtelności tematu.


Historia

Na projekcie migrowano kod Java z użyciem checked exceptions (np. IOException). Po migracji na Kotlin programista zapomniał obsłużyć wyjątek podczas pracy z plikami — aplikacja zaczęła się wykrzacza na rzeczywistych plikach, ponieważ nikt nie obsługiwał błędów I/O, sądząc, że kompilator ostrzeże, jak w Java.


Historia

Jeden z członków zespołu błędnie użył try/catch do kontroli przepływu i spowolnił działanie parsowania logów (łapał NumberFormatException dla każdej niepoprawnej linii — wydajność nagle spadła przy dużej ilości danych).


Historia

W projekcie dla JVM przez Kotlin wywoływano kod Java, który deklarował checked exceptions (throws). Kod Kotlin nie obsługiwał wyjątków, sądząc, że "wszystko jest unchecked" — w rezultacie krytyczny wyjątek został niezauważony aż do incydentu w produkcji.