Jason. Cała informatyka w jednym miejscu!

Przechodzimy do przedostatniego wątku związanego poniekąd z wartościami "null" i uprzedzam, że tym razem nie będzie wcale takich malutkich rozmiarów! Co może zająć dużo czasu na zrozumienie? Przechwytywanie wyjątków w języku Kotlin oraz znane słowa kluczowe "try", "catch" oraz "finally". Część wiedzy została pobrana z języka Java, a część została "doklejona" do języka którego się teraz uczymy i moim zadaniem jest Wam ją rzetelnie przedstawić. Trzymajcie się mocno zanim otworzycie ten wpis!

PRZECHWYTYWANIE WYJĄTKÓW W JĘZYKU KOTLIN TO "PRAWIE" JAK W JAVIE!

Ponoć "prawie" robi wielką różnicę. To powiedzonko sprawdza się tutaj w 100%. Jeśli "wracacie z Javy" i kumacie chociaż troszeczkę na czym polega przechwytywanie wyjątków, to dobrą wiadomością dla Was będzie to, że zdecydowana większość będzie znajoma. Większość, ale nie wszystko! Kotlin jest i w tych sprawach nieco oryginalny i posiada w sobie trochę więcej operacji niż Java, które trzeba poznać.

Umówimy się zatem tak. Krótko streszczę tę część wspólną jaką znajdziecie w obu językach, a w sprawie szczegółów odeślę Was do odpowiedniego artykułu. Skoncentruję się dużo bardziej na tej części "Kotlin only", bo uważam że nie ma sensu powtarzać tego, co pisałem jakiś czas temu. Zaczynamy!

CZĘŚĆ PIERWSZA. WSPÓLNA SKŁADNIA DLA JAVY I KOTLINA

W obrębie części pierwszej, przechwytywanie wyjątków w języku Kotlin wygląda DOKŁADNIE tak samo, jak w języku Java.

CO TO TAKIEGO TEN "WYJĄTEK"?

Wyjątek z definicji to sygnał wysyłany przez program, że w określonej instrukcji stało się coś nieoczekiwanego, bądź odstającego od normy. Przykładem jaki zawsze podaję za taką sytuację jest próba odczytania pliku, którego nie znaleziono. Instrukcją jest odczytanie pliku. Sytuacją nieoczekiwaną jest nieobecność wskazanego pliku. Wtedy zostaje zgłoszony wyjątek!

KLASA BAZOWA "EXCEPTION"

Jedna z najważniejszych informacji odnośnie samego wyjątku jest taka, że z programistycznego punktu widzenia to również jest obiekt! Konkretniej, obiekt pochodzący od klasy bazowej "Exception". Każdy wbudowany wyjątek dziedziczy od konkretnej "rodziny", które możemy przejrzeć w dokumentacji. Możemy także sami definiować własne niestandardowe wyjątki. Wystarczy nowa klasa i dziedziczenie od "Exception".

PRZECHWYTYWANIE WYJĄTKÓW JEST UŻYTECZNIEJSZE NIŻ MYŚLISZ

Przechwytywanie wyjątków przydaje się w momencie, gdy chcemy przejąć kontrolę nad przebiegiem programu kiedy dojdzie do zgłoszenia wyjątku. Możemy w ten sposób zapobiec "wyłożeniu się" programu i poinformować użytkownika o zaistniałej sytuacji w mniej brutalny sposób (język naturalny zamiast nazw klas wyjątków). Moja praktyka pokazała, że najbardziej się to przydaje w projektowaniu aplikacji z graficznym interfejsem użytkownika. Wtedy możemy przechwycone wyjątki oprawić w ładnie wyglądające komunikaty błędu i uprzedzić co poszło nie tak, własnymi słowami.

PROGRAMISTYCZNA "TRÓJCA"

Jeśli mowa jest o programowaniu przechwytywania wyjątków, na front wysuwają się trzy słowa kluczowe: "try", "catch" i "finally".

  • "try" to blok instrukcji "ryzykownych" czyli takich, które mogą się "wywalić" i zaburzyć normalny przebieg programu. Gdy zostanie w nim zgłoszony wyjątek, reszta instrukcji nie zostaje wykonana.
  • "catch" to blok instrukcji przeznaczony dla odpowiedniego typu wyjątku, w rozumieniu hierarchii dziedziczenia. Wykonuje się on zaraz po zgłoszeniu wyjątku w bloku "try" i tylko wtedy zostają wykonane tamtejsze instrukcje (jeśli wyjątek nie wystąpił, wtedy nie wykonuje się nic z bloku "catch"). Może być ich kilka naraz, z tym że zalecana jest taka kolejność "od najbardziej specyficznego do ogólnego", gdyż program "schodzi" od góry do dołu w poszukiwaniu odpowiadającego typu (ile go znajdzie).
  • Ostatnie słowo "finally" to część poboczna całej "triady" na którą poświęcony jest blok instrukcji wykonywanych dla obu przypadków bez względu na sytuację (kiedy doszło do wyjątku i kiedy wszystko przebiegło poprawnie).
"THROW" A "THROWS"

Ostatni akapit poświęcę na dwa dodatkowe słowa kluczowe jakie znajdziecie w Javie. Są to mianowicie: "throw" i "throws". Nie mylcie jednego z drugim. Mimo różnicy w literce "s", są to DWA ODRĘBNE słowa kluczowe! "throw" umożliwia jawne zgłoszenie dowolnego wyjątku w danym miejscu w kodzie, a "throws" to dekoracja wstawiana w nagłówek metody będąca sygnałem dla kompilatora, że w razie zgłoszenia w niej wyjątku, ma "zwalić" problem na metodę, która ją wywołała. Nie występuje to słowo w Kotlinie.

To było wyjaśnienie wszystkiego w pigułce. Więcej na temat przechwytywania wyjątków od strony języka Java znajdziecie w jednym z moich poprzednich artykułów, tak samo jak informacje o własnoręcznym prowokowaniu wyjątku oraz o "przerzuceniu" odpowiedzialności za wyjątek na metodę wywołującą.

CZĘŚĆ DRUGA. WYSTĘPOWANIE TYLKO W KOTLINIE

Teraz o wiele istotniejsza część materiału. Część, która obejmuje wyłącznie język Kotlin. Taka seria różnic i możliwości. Oto wszystkie przeze mnie wyłapane czynniki:

"FINALLY" ZASTĘPUJE "CATCH"!

Oto pierwsza okazja do opadnięcia kopary. Przechwytywanie wyjątków w języku Kotlin może zostać zrealizowane bez części obowiązkowej w Javie, "catch"! Mimo tego, że brak logiki w takim postępowaniu (co to za przechwytywanie jak pozbawiamy się części "przechwytującej"?), to taki manewr jest dozwolony:

try {
	println(12 / 0)
}
finally {
	println("Jakoś tak wyszło...")
}

ale wtedy "finally" już musi tam stać! Nie ma tak, że "try" zostawiamy samotnie.

ŻADNEGO DEFINIOWANIA "THROWS" W NAGŁÓWKU FUNKCJI!

Jedna z Waszych funkcji "przerzuca" odpowiedzialność za zgłoszony wyjątek funkcji wywołującej? Jeśli zapomnicie o klauzuli "throws" wymaganej w Javie, to w języku Kotlin jest to nawet oczekiwane. Tutaj nie jest wymagana żadna deklaracja w nagłówku, że Wasza funkcja może zgłosić taki i taki wyjątek. Nawet jest niewskazana, bo język Kotlin nie rozpoznaje ze swojej puli słowa kluczowego "throws" i wyskoczy błąd!

BRAK ROZRÓŻNIANIA WYJĄTKÓW WYMAGAJĄCYCH PRZECHWYTYWANIA OD TYCH NIEWYMAGAJĄCYCH

Prawdopodobnie obiło się Wam o uszy, że w Javie takie wyjątki jakie pochodzą od klasy "RuntimeException", nie wymagają obowiązkowych klauzul "try-catch". W języku Kotlin macie lepiej. Tutaj ŻADEN wyjątek nie wymaga obsłużenia, nawet kiedy przeprowadza się operacje ryzykowne np. próba otwarcia pliku o wskazanej ścieżce.

fun writeToFile() {
	val fw = FileWriter("test.txt")
	val bw = BufferedWriter(fw)

	bw.write("test")
	bw.close()
}

Skonfrontujcie to sobie z kodem źródłowym w języku Java. Na pewno będą się różnić!

PRZECHWYTYWANIE WYJĄTKÓW W JĘZYKU KOTLIN ODBYWA SIĘ NA WYRAŻENIU!

Pamiętacie wyrażenie "if" działające na identycznej zasadzie co operator warunkowy? A co jeśli napiszę, że Kotlin dopuszcza możliwość przechwytywania na podstawie wyrażenia? Zobaczcie prosty przykład:

val result = try {
	"12".toInt()
}
catch (e : Exception) {
	null
}

println(result)

Bardzo ciekawy fenomen. Kiedy konwersja łańcucha znaków na liczbę zakończy się sukcesem, zostanie przypisana prawidłowo skonwertowana wartość. W innym wypadku, zmienna przyjmie postać "null" (czyli typ będzie "Int?", gdyż powstaje ryzyko przypisania wartości "null"). Jeżeli bloki mają kilka instrukcji, to wartość zostanie pobrana od ostatniej instrukcji. Pamiętajcie, że jak dołożycie wywołanie funkcji za ostatnią instrukcję, to zmienna przyjmie adres funkcji!

ZGŁASZANIE WYJĄTKÓW Z OPERATOREM ELVIS

Operator Elvis już został przedstawiony. To wyobraźcie sobie teraz, że możecie go połączyć ze sprowokowaniem wyjątku słowem "throw":

val age = person?.age ?: throw Exception()

Wiecie już jak działa operator Elvis więc możecie sami domyślić się efektu.

TYP DANYCH "NICZEGO"

Ostatnia rzecz już tytułem ciekawostki niż spostrzeżenia. Może Wam się przydać na przyszłość taka informacja, że samo "null" to typ danych "Nothing":

val nothing: Nothing? = null

A ponieważ przypisujemy wartość "null", zmienna musi akceptować wartości puste więc...mamy w efekcie "Nothing?" (ze znaczkiem zapytania). Nawet "null" ma swój typ danych.

Przechwytywanie wyjątków w języku Kotlin

Przechwytywanie wyjątków w języku Kotlin pozwala na o wiele więcej manewrów bez wymuszania konieczności prewencyjnego zabezpieczania się klauzulą "try-catch"!


Dotarliście do mety! Spodziewałem się, że przechwytywanie wyjątków w języku Kotlin wymagać będzie znacznie więcej miejsca na treść niż tamte wpisy jednakże mam nadzieję, że o niczym nie zapomniałem i niczego nie popieprzyłem.

PODOBNE ARTYKUŁY