JavaRush /Blog Java /Random-PL /Wyjątki w Javie (wyjątek Java)

Wyjątki w Javie (wyjątek Java)

Opublikowano w grupie Random-PL
W życiu codziennym czasami zdarzają się sytuacje, których nie planowaliśmy. Na przykład wstajesz rano do pracy, szukasz ładowarki do telefonu, ale jej nie ma. Idziesz do łazienki umyć twarz – woda jest wyłączona. Wsiadłem do samochodu i nie odpalił. Ale człowiek jest w stanie dość łatwo poradzić sobie z takimi nieprzewidzianymi sytuacjami. W tym artykule postaramy się dowiedzieć, jak radzą sobie z nimi programy Java.

Jakie są wyjątki Java

W świecie programowania wystąpienie błędów i nieoczekiwanych sytuacji podczas wykonywania programu nazywa się wyjątkiem. W programie wyjątki mogą wystąpić w wyniku nieprawidłowych działań użytkownika, braku niezbędnego zasobu na dysku lub utraty połączenia z serwerem przez sieć. Wyjątki podczas wykonywania programu mogą być również spowodowane błędami programistycznymi lub nieprawidłowym użyciem API. W przeciwieństwie do naszego świata, program musi jasno wiedzieć, co zrobić w takiej sytuacji. W tym celu Java udostępnia mechanizm wyjątków.

Krótko o słowach kluczowych spróbuj, złap, wreszcie rzuty

Obsługa wyjątków w Javie opiera się na zastosowaniu w programie następujących słów kluczowych:
  • try - definiuje blok kodu, w którym może wystąpić wyjątek;
  • catch – definiuje blok kodu, w którym obsługiwany jest wyjątek;
  • wreszcie – definiuje blok kodu, który jest opcjonalny, ale jeśli jest obecny, i tak jest wykonywany, niezależnie od wyników bloku try.
Te słowa kluczowe służą do tworzenia specjalnych konstrukcji przetwarzających w kodzie programu: try{}catch, try{}catch{}w końcu, try{}w końcu{}.
  • rzut – używany do zgłoszenia wyjątku;
  • rzuty – używane w sygnaturach metod, aby ostrzec, że metoda może zgłosić wyjątek.
Przykład użycia słów kluczowych w programie Java:
//metoda odczytuje ciąg znaków z klawiatury

public String input() throws MyException {//ostrzegaj rzutami,
// że metoda może zgłosić MyException
      BufferedReader reader = new BufferedReader(new InputStreamReader(System.in));
    String s = null;
// w bloku try umieszczamy kod, w którym może wystąpić wyjątek, w this
// jeśli kompilator powie nam, że metoda readLine() klasy
// BufferedReader może zgłosić wyjątek I/O
    try {
        s = reader.readLine();
// w bloku catch umieszczamy kod obsługujący wyjątek IOException
    } catch (IOException e) {
        System.out.println(e.getMessage());
// zamknij strumień odczytu w bloku ostatecznie
    } finally {
// podczas zamykania strumienia możliwy jest również wyjątek, np. jeśli nie został otwarty, więc „zawijamy” kod w bloku try
        try {
            reader.close();
// obsługa wyjątków zapisu podczas zamykania strumienia odczytu
        } catch (IOException e) {
            System.out.println(e.getMessage());
        }
    }

    if (s.equals("")) {
// uznaliśmy, że pusty string może w przyszłości zakłócić pracę naszego programu, np. na wynik tej metody musimy wywołać metodę substring(1,2), więc jesteśmy zmuszeni przerwać program wykonanie z generowaniem naszego typu wyjątku MyException za pomocą throw
        throw new MyException("String can not be empty!");
    }
    return s;
}

Dlaczego potrzebujemy mechanizmu wyjątków?

Spójrzmy na przykład z prawdziwego świata. Wyobraźmy sobie, że na autostradzie znajduje się odcinek z mostem awaryjnym o ograniczonej nośności. Jeśli najedzie na niego pojazd o masie przekraczającej nośność mostu, może się on zawalić, a sytuacja kierowcy może stać się, delikatnie mówiąc, wyjątkowa. Aby temu zapobiec, służby drogowe z wyprzedzeniem instalują na drodze znaki ostrzegawcze. Kierowca samochodu patrząc na znak ostrzegawczy porówna masę swojego samochodu z dopuszczalną masą przejazdu po moście. Jeśli przekroczy, pojedzie objazdem. Dzięki działaniom służb drogowych kierowcy ciężarówek, po pierwsze, otrzymali możliwość wcześniejszej zmiany trasy, po drugie, zostali ostrzeżeni o niebezpieczeństwie na głównej trasie, a wreszcie zostali uprzeczeni o niemożności korzystania z przejazdu. most pod pewnymi warunkami.
Исключения в Java - 2
Możliwość zapobiegania i rozwiązywania wyjątków w programie, aby mógł on działać dalej, jest jednym z powodów używania wyjątków w Javie. Mechanizm wyjątków pozwala również chronić napisany kod (interfejs programowania) przed niewłaściwym użyciem przez użytkownika poprzez walidację (sprawdzanie) przychodzących danych. A teraz bądźmy na chwilę policją drogową. Na początek warto poznać miejsca, w których kierowcy mogą wpaść w kłopoty. Po drugie, musisz przygotować i zainstalować znaki ostrzegawcze. Na koniec należy zapewnić objazdy na wypadek zagrożenia na trasie głównej. W Javie mechanizm wyjątków działa w podobny sposób. Na etapie tworzenia programu „chronimy” niebezpieczne fragmenty kodu przed wyjątkami za pomocą bloku try{}, udostępniamy ścieżki „zapasowe” za pomocą bloku catch{}, a w bloku final{} piszemy kod, który jest wykonywany w program dla dowolnego rezultatu. W przypadkach, gdy nie możemy zapewnić „drogi awaryjnej” lub świadomie chcemy pozostawić wybór użytkownikowi, musimy przynajmniej ostrzec go o niebezpieczeństwie. Dlaczego? Wyobraźcie sobie oburzenie kierowcy, który dojeżdża do mostu awaryjnego, przez który nie da się przejechać, nie widząc po drodze ani jednego znaku ostrzegawczego! W programowaniu, pisząc nasze klasy i metody, nie zawsze możemy przewidzieć kontekst ich użycia przez innych programistów w ich programach, więc nie możemy przewidzieć w 100% prawidłowego sposobu rozwiązania wyjątku. Jednocześnie dobrą praktyką jest ostrzeganie użytkowników naszego kodu o możliwości wystąpienia wyjątku. Mechanizm wyjątków w Javie pozwala nam to zrobić za pomocą rzutów — zasadniczo deklarując ogólne zachowanie naszej metody w celu zgłoszenia wyjątku, pozostawiając w ten sposób użytkownikowi metody napisanie kodu obsługującego wyjątek w Javie.

Ostrzeżenie o „kłopotach”

Jeśli nie planujesz obsługiwać wyjątku w swojej metodzie, ale chcesz ostrzec użytkowników metody o możliwych wyjątkach, użyj słowa kluczowego rzuca. To słowo kluczowe w sygnaturze metody oznacza, że ​​w pewnych warunkach metoda może zgłosić wyjątek. To ostrzeżenie jest częścią interfejsu metody i daje użytkownikowi prawo do dostosowania implementacji procedury obsługi wyjątków. Po rzutach wskazujemy typ zgłaszanego wyjątku. Są to zazwyczaj elementy potomne klasy wyjątków Java . Ponieważ Java jest językiem obiektowym, wszystkie wyjątki w Javie są obiektami.
Исключения в Java - 3

Hierarchia wyjątków Java

Gdy podczas wykonywania programu wystąpi błąd, środowisko wykonawcze JVM tworzy obiekt żądanego typu z hierarchii wyjątków Java - zestawu możliwych wyjątków odziedziczonych od wspólnego „przodka” - klasy Throwable. Wyjątkowe sytuacje występujące w programie można podzielić na dwie grupy:
  1. Sytuacje, w których przywrócenie dalszego normalnego działania programu jest niemożliwe
  2. Odzyskiwanie jest możliwe.
Do pierwszej grupy zaliczają się sytuacje, w których występują wyjątki odziedziczone z klasy Error . Są to błędy, które pojawiają się podczas wykonywania programu w wyniku awarii maszyny JVM, przepełnienia pamięci lub awarii systemu. Zwykle wskazują na poważne problemy, których nie można naprawić za pomocą oprogramowania. Ten typ wyjątku w Javie jest klasyfikowany jako niesprawdzony na etapie kompilacji. Do tej grupy zalicza się również RuntimeException - wyjątki, dziedzice klasy Wyjątek , generowane przez maszynę JVM podczas wykonywania programu. Często są one spowodowane błędami programistycznymi. Te wyjątki są również odznaczane w czasie kompilacji, więc pisanie kodu do ich obsługi nie jest konieczne. Do drugiej grupy zaliczają się sytuacje wyjątkowe, które są przewidziane na etapie pisania programu i dla których trzeba napisać kod przetwarzający. Takie wyjątki są sprawdzane. Większość pracy programisty Java związanego z wyjątkami polega na obsłudze takich sytuacji.

Tworzenie wyjątku

Podczas wykonywania programu maszyna JVM zgłasza wyjątek lub ręcznie za pomocą instrukcji rzutu . Tworzy to obiekt wyjątku w pamięci i przerywa wykonywanie głównego kodu programu, podczas gdy moduł obsługi wyjątków JVM próbuje znaleźć sposób na obsłużenie wyjątku.

Obsługa wyjątków

Tworzenie bloków kodu, dla których zapewniamy obsługę wyjątków w Javie, odbywa się w programie za pomocą konstrukcji try{}catch, try{}catch{}finally, try{}finally{}.
Исключения в Java - 4
Gdy w bloku try zostanie zgłoszony wyjątek, procedura obsługi wyjątku jest wyszukiwana w następującym bloku catch. Jeśli catch zawiera procedurę obsługi tego typu wyjątku, kontrola przechodzi do niego. Jeśli nie, JVM szuka procedury obsługi tego typu wyjątku w łańcuchu wywołań metod, aż do znalezienia odpowiedniego catch. Po wykonaniu bloku catch sterowanie przekazywane jest do opcjonalnego bloku Final . Jeśli nie zostanie znaleziony odpowiedni blok catch, JVM zatrzymuje wykonywanie programu i wyświetla stos wywołań metod - stack tracie , po wcześniejszym wykonaniu kodu bloku final, jeśli jest obecny. Przykład obsługi wyjątków:
public class Print {

     void print(String s) {
        if (s == null) {
            throw new NullPointerException("Exception: s is null!");
        }
        System.out.println("Inside method print: " + s);
    }

    public static void main(String[] args) {
        Print print = new Print();
        List list= Arrays.asList("first step", null, "second step");

        for (String s:list) {
            try {
                print.print(s);
            }
            catch (NullPointerException e) {
                System.out.println(e.getMessage());
                System.out.println("Exception was processed. Program continues");
            }
            finally {
                System.out.println("Inside bloсk finally");
            }
            System.out.println("Go program....");
            System.out.println("-----------------");
        }

    }
    }
Wyniki metody głównej :
Inside method print: first step
Inside bloсk finally
Go program....
-----------------
Exception: s is null!
Exception was processed. Program continues
Inside bloсk finally
Go program....
-----------------
Inside method print: second step
Inside bloсk finally
Go program....
-----------------
Blok finallyjest zwykle używany do zamykania strumieni otwartych w bloku try lub do zwalniania zasobów. Jednak podczas pisania programu nie zawsze można śledzić zamknięcie wszystkich zasobów. Aby ułatwić nam życie, programiści Java zaproponowali nam konstrukcję try-with-resources, która automatycznie zamyka zasoby otwarte w bloku try. Nasz pierwszy przykład można przepisać w następujący sposób try-with-resources:
public String input() throws MyException {
    String s = null;
    try(BufferedReader reader = new BufferedReader(new InputStreamReader(System.in))){
        s = reader.readLine();
   } catch (IOException e) {
       System.out.println(e.getMessage());
   }
    if (s.equals("")){
        throw new MyException ("String can not be empty!");
    }
    return s;
}
Dzięki możliwościom Javy, począwszy od wersji 7, możemy także połączyć w jednym bloku wychwytywanie różnych typów wyjątków, dzięki czemu kod będzie bardziej zwarty i czytelny. Na przykład:
public String input() {
    String s = null;
    try (BufferedReader reader = new BufferedReader(new InputStreamReader(System.in))) {
        s = reader.readLine();
        if (s.equals("")) {
            throw new MyException("String can not be empty!");
        }
    } catch (IOException | MyException e) {
        System.out.println(e.getMessage());
    }
    return s;
}

Wyniki

Zastosowanie wyjątków w Javie pozwala zwiększyć odporność programu na błędy poprzez zastosowanie ścieżek „zapasowych”, oddzielenie logiki kodu głównego od kodu obsługującego wyjątki poprzez zastosowanie bloków catch, a także daje nam możliwość możliwość delegowania obsługi wyjątków użytkownikowi naszego kodu za pomocą rzutów.
Komentarze
TO VIEW ALL COMMENTS OR TO MAKE A COMMENT,
GO TO FULL VERSION