Lekcja 16. Obsługa wyjątków (try, catch, throw, finally)
Trudny / egzaminacyjnyPo co się tego uczymy?
Prawdziwe aplikacje, z jakimi zetkniesz się na egzaminie i w pracy, muszą działać niezawodnie nawet przy błędnych danych wejściowych — program, który "wywala się" na pierwszym literówce użytkownika, nie nadaje się do użytku. Obsługa wyjątków to profesjonalny standard, którego oczekuje się w każdym poważniejszym kodzie.
Teoria
Do tej pory zakładaliśmy, że program zawsze dostaje poprawne dane. W praktyce użytkownik może wpisać tekst zamiast liczby, plik może nie istnieć, dzielenie może wystąpić przez zero. Bez obsługi błędów każda taka sytuacja "wywala" (crashuje) cały program. Wyjątki to mechanizm C# do BEZPIECZNEGO reagowania na takie sytuacje.
Wyjątek (Exception) to obiekt reprezentujący błąd, który wystąpił w trakcie działania programu — np. DivideByZeroException (dzielenie przez zero), IndexOutOfRangeException (indeks poza zakresem tablicy, Lekcja 8), FormatException (nieudana konwersja tekstu na liczbę), FileNotFoundException (brak pliku, Lekcja 9).
Blok try-catch:
try { kod, który może zgłosić błąd } catch (TypWyjatku e) { co zrobić w razie błędu }
Jeśli w bloku try wystąpi błąd, program NATYCHMIAST przeskakuje do pasującego bloku catch, zamiast zakończyć działanie awaryjnie. Zmienna e (obiekt wyjątku) zawiera m.in. e.Message — tekstowy opis, co dokładnie poszło nie tak.
finally to opcjonalny blok wykonywany ZAWSZE po try/catch, niezależnie od tego, czy wystąpił błąd — używany np. do zamykania plików czy połączeń, które muszą zostać zwolnione bez względu na wynik.
throw pozwala Twojemu WŁASNEMU kodowi celowo zgłosić wyjątek, gdy wykryje sytuację, której nie da się sensownie kontynuować:
if (wiek < 0) { throw new ArgumentException("Wiek nie może być ujemny"); }
Schemat
try
{
// kod, który MOŻE zgłosić błąd (wyjątek)
}
catch (TypWyjatku e)
{
// co zrobić, gdy błąd wystąpi - program NIE PADA, tylko wchodzi tutaj
}
finally
{
// wykonuje się ZAWSZE, niezależnie czy był błąd czy nie
}
Przykład z życia
Kiedy aplikacja bankowa pokazuje komunikat "Nieprawidłowy format numeru karty" zamiast się zawiesić, właśnie działa mechanizm try-catch — program WYKRYŁ problem i zareagował w kontrolowany sposób, zamiast ulec awarii.
Kod (C#)
using System;
class Program
{
static void Main()
{
Console.Write("Podaj swój wiek: ");
string wejscie = "abc"; // symulacja błędnych danych od użytkownika
try
{
int wiek = int.Parse(wejscie); // może zgłosić FormatException
if (wiek < )
{
throw new ArgumentException("Wiek nie może być ujemny.");
}
Console.WriteLine("Twój wiek to: " + wiek);
}
catch (FormatException)
{
Console.WriteLine("Błąd: to nie jest poprawna liczba.");
}
catch (ArgumentException e)
{
Console.WriteLine("Błąd: " + e.Message);
}
finally
{
Console.WriteLine("Zakończono próbę odczytu wieku.");
}
Console.WriteLine("Program działa dalej, mimo błędu powyżej.");
}
}
Komentarz i wyjaśnienie kodu
int.Parse(wejscie) zgłasza FormatException, gdy tekst nie da się zamienić na liczbę — dokładnie to symuluje ten przykład, wpisując na sztywno tekst "abc". Zwróć uwagę, że można mieć WIELE bloków catch dla różnych typów wyjątków — C# sprawdza je po kolei i wykonuje pierwszy pasujący. Blok finally wykonał się bez względu na to, czy błąd wystąpił — to jego kluczowa cecha.
Ćwiczenie samodzielne
Napisz program próbujący podzielić dwie liczby (jedną z nich ustaw na 0) w bloku try-catch, przechwytujący DivideByZeroException.
Plac zabaw — wypróbuj online
Poniższy kod wykonuje się od razu w Twojej przeglądarce — nic nie trzeba instalować. Zmień kod i kliknij „Uruchom”.
Zadania do pracy własnej
Napisz program próbujący odczytać element tablicy pod indeksem spoza jej zakresu, obsługując
IndexOutOfRangeExceptionkomunikatem "Nie ma elementu o takim indeksie".Napisz metodę
WalidujWiek(int wiek), która rzuca wyjątekArgumentException, jeśli wiek jest ujemny lub większy niż 130, i obsłuż to wywołanie blokiem try-catch wMain().Zbuduj klasę
KontoBankowe(z Lekcji 11), w której metodaWyplac()RZUCA własny wyjątek (np. utworzoną przez Ciebie klasęNiewystarczajaceSrodkiException : Exception) zamiast tylko wypisywać komunikat, gdy brakuje środków — i obsłuż to wywołanie wMain(), wypisując komunikat z wyjątku.
Typowe błędy
Częsty błąd to "połykanie" wyjątków pustym blokiem catch { } bez żadnej reakcji — program pozornie działa dalej, ale problem znika bez śladu, co bardzo utrudnia późniejsze debugowanie. Drugi błąd: używanie try-catch do obsługi sytuacji, które powinny być sprawdzone WCZEŚNIEJ zwykłym warunkiem if (np. sprawdzanie if (dzielnik != 0) zamiast łapania DivideByZeroException) — wyjątki są kosztowne wydajnościowo i powinny obsługiwać sytuacje NIETYPOWE, nie codzienną logikę. Trzeci: zbyt ogólny catch (Exception e) łapiący WSZYSTKIE możliwe błędy naraz, zamiast precyzyjnie obsłużyć konkretne, spodziewane typy wyjątków.
Nawiązanie do egzaminu zawodowego
To bezpośrednia realizacja efektu INF.04.4.9 z podstawy programowej: "programuje obsługę wyjątków" — wprost wymienia try/catch, throw oraz listę błędów wykonania jako wymagany zakres.