JavaRush /Blog Java /Random-PL /Wyjątki w Javie
Roman
Poziom 33

Wyjątki w Javie

Opublikowano w grupie Random-PL
Kiedy natknąłem się na temat „Wyjątki” pojawiło się wiele pytań, na które musiałem szukać odpowiedzi w różnych zakątkach Internetu, aby szczegółowo zrozumieć, jak to wszystko działa. W rezultacie przygotowałem własne wyjaśnienie, które może być bardziej zrozumiałe dla początkujących, którzy właśnie zetknęli się z tym zjawiskiem. Wyjątki w Javie — 1W komputerach przerwanie to sygnał przychodzący do procesora informujący o wystąpieniu zdarzenia wymagającego natychmiastowej reakcji. Sygnał przerwania wymaga, aby procesor wstrzymał działający program, aby można go było kontynuować nieco później, to znaczy komputer musi zapamiętać wszystkie informacje związane z wykonaniem programu. Takie przerwy są tymczasowe, jeśli nie śmiertelne. Takie przerwy mogą być spowodowane kodem programu lub jakąś funkcjonalnością sprzętu (na przykład zwykłym naciśnięciem klawiszy na klawiaturze; timerami, na przykład automatycznie wyłączającymi komputer). Liczba przerwań jest ograniczona do określonej liczby, wbudowanej w produkcję konkretnego procesora, to znaczy przydzielane są do tego specjalne „kanały” komunikacyjne, umożliwiające dostęp do procesora z pominięciem wszystkich innych procesów. Przerwania są generowane automatycznie również wtedy, gdy w wykonywanym kodzie programu wystąpi błąd (na przykład, jeśli nastąpi dzielenie przez zero). Takie zakłócenia są tradycyjnie nazywane pułapkami lub wyjątkami . W takich przypadkach zwyczajowo mówi się: „Zgłoszono wyjątek”, to znaczy uruchomiono wyjątek lub zgłoszono (zgłoszono) wyjątek , czyli żądanie przerwaniaz pytaniem „co robić?” wysłane do procesora. W tym momencie procesor przestaje działać, pamiętając moment, w którym się zatrzymał, a raczej skupienie kolejnej komórki, z której należy wykonać informację. Zapamiętywany jest cały łańcuch instrukcji wykonanych i NIEwykonanych. Następnie procesor odczytuje z pamięci instrukcje dotyczące działania w przypadku takiego błędu. Zgodnie z tą instrukcją może wprowadzać nowe wartości do niektórych klastrów, dodawać łańcuchy działań lub nowy cykl (na przykład cykl powrotu lub pętli) itp., czyli w zależności od wcześniej ułożonego błędu wykonywane są instrukcje down. Sam system komputerowy ma wbudowanych wiele automatycznych przerwań, które wyzwalane są po określonym czasie, na przykład w celu sterowania procesami działającymi na komputerze lub uruchamiania ustawionych alarmów, zbierania przychodzących sygnałów zewnętrznych i różnych konwerterów danych. Warto pamiętać, że duża liczba Przerwań z wielu powodów może całkowicie „zawiesić” system. Błąd w kodzie programu automatycznie spowoduje przerwanie pracy procesora, który będzie próbował przetworzyć zgodnie z zadanymi instrukcjami. Jednak nie wszystkie przerwania są przeznaczone do ich obsługi, w przeciwnym razie może wygenerować procedurę, która nam nie odpowiada, np. po prostu spowoduje zawieszenie aplikacji. Dlatego w programowaniu istnieje możliwość zorganizowania własnego przerwania dla określonej części kodu, w której programista potencjalnie widzi możliwość wystąpienia błędu. W takim przypadku błąd zostanie przetworzony w programie i nie skontaktuje się z procesorem w celu uzyskania instrukcji przetwarzania. Definicja takich bloków jest zorganizowana poprzez utworzenie obiektu „Wyjątek” . Obiekt ten jest automatycznie tworzony w bloku try-catch. Blok >tryjest sprawdzany pod kątem obecności błędu i jeśli taki występuje, program przechodzi do bloku catch, w którym podejmowane są działania mające na celu zapobieżenie lub zniwelowanie błędu. Przykładowo, jeśli z klawiatury wpiszemy Liczby , które trzeba później dodać i odjąć, to wpisanie z klawiatury Liter sprawi, że nie będzie można ich dodać za pomocą Liczb (sumę tych dwóch zmiennych oznaczmy literą S). Dlatego jako zespół trymusimy sprawdzić, czy liczbę A zawierającą Liczby można dodać do liczby B zawierającej Litery (czyli S = A + B), a jeśli nie jest to możliwe, a wręcz niemożliwe, to pewne należy podjąć środki, aby Błędy się NIE wydarzyły i nowe przerwanie z pytaniem „co robić?” nie poleciało do procesora. Jeżeli w programie nie ma Wyjątku, jego wykonanie zostanie przerwane przez procesor. Jeśli zajdzie Wyjątek, gdy zostanie „złapany” przez polecenie try, sterowanie przechodzi do polecenia catch, które może ustawić alternatywne rozwiązanie, np. nie będziemy dodawać tych dwóch liczb, ale ustawiamy S = A.
int a = 4;
String b = “hello”;
int S = 0;
 try {
   S = a + b;
   int r = 1;
 } catch (Exception igogo1) {
   S = a;
 }
 return S;
/* ciąg „int r = 1;” nie jest wykonywany, ponieważ wystąpił błąd, a program przekierowuje pracę bezpośrednio do modułu obsługi wyjątków (blok catch*/ Zatem obecność wyjątków jest okazją do rozwiązania problemu w programie bez wyrzucania go na poziom procesora. Obiekt „Exception”, który tworzony jest automatycznie w bloku tryw przypadku wykrycia błędu, zawiera wartość typu błędu. Nazwijmy to „NaszymWyjątkiem” – dla naszego konkretnego przypadku z opisem naszego konkretnego błędu. Twórcy języka Java stworzyli z góry pewną listę typowych błędów i typowe możliwości ich naprawienia, czyli w Javie istnieje pewna biblioteka wyjątków , do której możemy się zwrócić, aby obsłużyć zaistniały błąd, tak jak abyśmy sami nie pisali kodu przetwarzającego i dlatego OurException najprawdopodobniej już ktoś został opisany, więc musimy tylko znać nazwę, który z tych wyjątków wstawić do naszego programu, aby obsłużył kod, w którym potencjalnie mogłaby wystąpić awaria. Jeżeli popełnimy błąd i wybierzemy z biblioteki błędny wyjątek , to handler go nie „złapie”, błąd nie znajdzie rozwiązania w programie i żądanie zostanie wysłane do procesora. Ale jest sposób dla leniwych. Jeśli nie znamy nazwy wyjątku, którego potrzebujemy z biblioteki, możemy przyjąć ogólny o nazwie „ Wyjątek ”, jak w przykładzie opisanym powyżej. Ten wyjątek jest w stanie obsłużyć każdy rodzaj błędu, ale nie jest w stanie dostarczyć konkretnych informacji o zdarzeniu, które moglibyśmy zarejestrować. Biblioteka wcześniej napisanych wyjątków składa się z zaznaczonych i niesprawdzonych wyjątków . Sprawdzalne to takie, które można poprawić bez przerywania pracy programu, czyli jeśli spróbujemy otworzyć plik w folderze, w którym go nie ma, system nas o tym poinformuje, możemy plik upuścić do żądanego folderu i kontynuuj program. Oznacza to, że w rzeczywistości do procesora wysłano żądanie przerwania , ale bez pytania: „poszukaj, co zrobić z tym problemem?!?!!” Wysłaliśmy wykryte przez nas przerwanie z gotową instrukcją, którą procesor przetworzył i kontynuował wykonywanie programu. Niezaznaczone zostaną te błędy, których nie można poprawić, a program zostanie zamknięty przed zakończeniem, to znaczy do procesora zostanie wysłane żądanie przerwania, co w każdym przypadku przerwie wykonanie programu. Jedynym celem napisania takich wyjątków w programie jest umożliwienie użytkownikowi zrozumienia, co się stało, ponieważ po wyłapaniu tego zakłócenia możemy wyświetlić na ekranie komunikat informacyjny, dlatego program się zawiesił. Drugim powodem wyłapywania takich zakłóceń jest możliwość zapisania ich w logach do późniejszej analizy (został zhakowany, ale przynajmniej wiesz gdzie). Konsekwencją istnienia takich bibliotek jest konieczność pamiętania o ich uwzględnieniu. (Lista zaznaczonych i niesprawdzonych wyjątków z bibliotekami znajduje się na przykład tutaj ) Jeśli nie wiemy dokładnie, którą bibliotekę uwzględnić lub istnieje kilka opcji błędu, możemy catchwypisać wymagane wyjątki w kilku. System sam wybierze właściwą procedurę obsługi, jeśli znajduje się ona na liście. Zamiast konkretnego wyjątku możesz napisać ogólny „ Wyjątek ”, który obsłuży dowolny typ wyjątku , jeśli nie został przetworzony w poprzednich blokach.
int a = 4;
String b = “hello”;
int S = 0;
 try {
   S = a + b;
   int r = 1;
 }
catch(NullPointerException blabla2) {
   System.out.println("Exception handling code for the NullPointerException.");
 }
catch (ArithmeticException ex1) {
   S = a;
 }
catch(Exception uups1) {
   System.out.println("Exception occured");
 }
 return S;
Jeśli istnieje blok, tryautomatycznie tworzony jest wyjątek. Jeśli w pewnym momencie będziemy musieli wymusić wyjątek , wówczas używane jest polecenie throw. Oznacza to, że samodzielnie tworzymy obiekt new throw… po czym program zatrzymuje pracę, wysyła do procesora żądanie przerwania i zostaje przeniesiony do sekcji programu catch, skąd próbuje uzyskać instrukcje dotyczące dalszych działań. Tworząc ręcznie wyjątek , możemy określić jego konkretny typ z biblioteki:

throw new ArithmeticException("Access denied - You must be at least 18 years old.");
następnie procedura obsługi będzie szukać bloku catchz tym konkretnym wyjątkiem - przeszukaj cały program, ze wszystkich stron catch. Po throwwydaniu polecenia obsługi wyjątku cały pozostały kod programu NIE zostanie wykonany, z wyjątkiem tego, który znajduje się w bloku catch. Jeśli w programie nie zostanie odnaleziona procedura obsługi, procesorowi zadawane jest pytanie: „sam zdecyduj, co zrobić” i przerywa działanie programu. Wywołanie new throw... można wykonać zarówno wewnątrz >try, jak i na zewnątrz bloku (w dowolnym miejscu programu)
try {
   /* функция Lub действие, в котором есть сомнения. То есть: «попробуй выполнить это, а если не получится, а, если не получится, запускай режим исключения» */
   throw new CallForException(); /* Назначаем исключение, которое будет работать в случае наличия ошибки в функции, описанной выше. Здесь исключение «CallForException» - берется из библиотеки существующих исключений */
} catch (CallForException ee1) {
   /* Корректируем ошибку, чтобы программа не «отвалилась» Lub выводим сообщение об ошибке Lub что-то ещё */
} finally {
   /* этот блок работает всегда независимо от того была ошибка Lub нет. А если была, то сработало ли решение в catch Lub нет */
   /* часто используется для подчистки хвостов, например, для закрытия запущенного plik Lub базы данных */
   /* в ряде случаев блок catch вообще может быть опущен и оставлен только блок finally и наоборот finally может быть опущен и оставлен только catch */
   /* Не допускается использование этого блока в ряде случаев, например, когда функция System.exit() запущена Lub другие системные Исключения, типа «отключение электроэнергии» и т.п. */
}

Powiadomienie o wyjątkach

Metody napisane wcześniej przez kogoś mogą obejmować zgłaszanie wyjątków. Na wszelki wypadek programista, który napisał kod, ostrzegał kolejnych programistów, że w napisanej przez niego metodzie może wystąpić błąd. I tak np. opisany poniżej sposób tworzenia pliku zakłada, że ​​podczas tworzenia pliku może wystąpić błąd (pod podaną ścieżką nie ma pliku), co oznacza, że ​​potrzebny będzie program obsługi błędów:
public void createFile(String path, String text) throws IOException {
    FileWriter writer = new FileWriter(path, true);
    writer.write(text);
    writer.close();
}
Ale jednocześnie nie ma samego handlera, co oznacza, że ​​​​teraz nie będziemy mogli po prostu wywołać zapisanej metody w naszym programie w trybie normalnym. Teraz musimy napisać procedurę obsługi błędów i wywołać tę metodę w bloku try:
String filePath = "hello.txt";
String text = "Hello World";

try {
    createFile(filePath, text);
} catch (IOException ex) {
    System.err.println("Error creating file: " + ex);
}

Rodzime wyjątki

Istnieje możliwość napisania własnych wyjątków obsługujących określone błędy, jeśli istniejące biblioteki nie są dla nas wystarczające. Aby to zrobić, po prostu tworzymy klasę, która dziedziczy po klasie wyjątku
public class StudentNotFoundException extends Exception {

    public StudentNotFoundException (String message) {
        super(message);
    }
}
Tworząc własne wyjątki, należy pamiętać o dwóch zasadach:
  1. Nazwa naszej klasy musi kończyć się na „Exception”
  2. Klasa musi zawierać konstruktor ze zmienną łańcuchową opisującą szczegóły problemu wyjątku. W konstruktorze wywoływany jest superkonstruktor i przekazywany jest komunikat.
Przykład wykorzystania wygenerowanego wyjątku:
public class StudentManager {
    public Student find(String studentID) throws StudentNotFoundException {
        if (studentID.equals("123456")) {
            return new Student();
        } else {
            throw new StudentNotFoundException(
                "Could not find student with ID " + studentID);
        }
    }
}
Łapiemy ten wyjątek za pomocą kodu:
public class StudentTest {
    public static void main(String[] args) {
        StudentManager manager = new StudentManager();
         try {
            Student student = manager.find("0000001");
        } catch (StudentNotFoundException ex) {
            System.err.print(ex);
        }
    }
}
Wynikiem wykonania programu będzie: StudentNotFoundException: Nie można znaleźć ucznia o identyfikatorze 0000001

Dlaczego musisz pisać wyjątki?

W 1996 roku rakieta Ariane 5 rozbiła się z powodu nieprawidłowej konwersji zmiennej pływakowej na zmienną całkowitą. Nie było wyjątków ani sposobów obsługi tej sytuacji. Jeśli podczas pobierania pliku nastąpi utrata połączenia z Internetem, obecność wyjątku umożliwi kontynuację pobierania po przywróceniu połączenia. Jeśli nie ma wyjątku, pobieranie będzie musiało rozpocząć się od nowa.

Bibliografia:

Komentarze
TO VIEW ALL COMMENTS OR TO MAKE A COMMENT,
GO TO FULL VERSION