Cześć! W dzisiejszej lekcji porozmawiamy o wyjątkach Java. Codzienność pełna jest sytuacji, których nie jesteśmy w stanie przewidzieć. Na przykład wstajesz rano do pracy i szukasz ładowarki do telefonu, ale nigdzie nie możesz jej znaleźć. Idziesz do łazienki pod prysznic i odkrywasz, że rury są zamarznięte. Wsiadasz do samochodu, ale nie chce się uruchomić. Człowiek jest w stanie dość łatwo poradzić sobie z takimi nieprzewidzianymi okolicznościami. W tym artykule postaramy się dowiedzieć, jak radzą sobie z nimi programy Java.
Możliwość zapobiegania i rozwiązywania wyjątkowych sytuacji w programie, pozwalająca na jego dalsze działanie, jest jednym z powodów używania wyjątków w Javie. Mechanizm wyjątków pozwala również chronić swój kod (API) przed niewłaściwym użyciem poprzez walidację (sprawdzanie) wszelkich danych wejściowych. Teraz wyobraź sobie, że jesteś działem transportu przez sekundę. Po pierwsze, musisz znać miejsca, w których kierowcy mogą spodziewać się kłopotów. Po drugie, musisz stworzyć i zainstalować znaki ostrzegawcze. I wreszcie, musisz zapewnić objazdy, jeśli pojawią się problemy na głównej trasie. W Javie mechanizm wyjątków działa w podobny sposób. Podczas programowania używamy bloku try , aby zbudować „bariery wyjątków” wokół niebezpiecznych sekcji kodu, zapewniamy „trasy zapasowe” za pomocą catch {}bloku i piszemy kod, który powinien działać bez względu na wszystko w bloku ultimate{} . Jeśli nie możemy zapewnić „trasy zapasowej” lub chcemy dać użytkownikowi prawo wyboru, musimy przynajmniej ostrzec go o niebezpieczeństwie. Dlaczego? Wyobraźcie sobie oburzenie kierowcy, który nie widząc ani jednego znaku ostrzegawczego wjeżdża na mały mostek, którego nie może przejechać! W programowaniu, pisząc nasze klasy i metody, nie zawsze jesteśmy w stanie przewidzieć, jak mogą zostać użyte przez innych programistów. W rezultacie nie możemy przewidzieć w 100% poprawnego sposobu rozwiązania wyjątkowej sytuacji. To powiedziawszy, dobrze jest ostrzec innych o możliwości wystąpienia wyjątkowych sytuacji. Mechanizm wyjątków Javy pozwala nam to zrobić za pomocą rzutówsłowo kluczowe — zasadniczo deklaracja, że ogólne zachowanie naszej metody obejmuje zgłaszanie wyjątku. Dlatego każdy, kto korzysta z tej metody, wie, że powinien napisać kod obsługujący wyjątki.
zostanie zgłoszony wyjątek , JVM szuka odpowiedniej procedury obsługi wyjątku w następnym bloku catch . Jeśli blok catch ma wymaganą procedurę obsługi wyjątków, sterowanie jest do niego przekazywane. Jeśli nie, JVM szuka dalej w łańcuchu bloków catch , aż do znalezienia odpowiedniego modułu obsługi. Po wykonaniu bloku catch sterowanie jest przekazywane do opcjonalnego bloku ostatecznie . Jeśli odpowiedni połówblok nie zostanie znaleziony, wówczas JVM zatrzymuje program i wyświetla ślad stosu (bieżący stos wywołań metod), po pierwszym wykonaniu bloku ultimate , jeśli istnieje. Przykład obsługi wyjątków:
Co to jest wyjątek Java?
W świecie programowania błędy i nieprzewidziane sytuacje w wykonywaniu programu nazywane są wyjątkami. W programie mogą wystąpić wyjątki z powodu nieprawidłowych działań użytkownika, niewystarczającej ilości miejsca na dysku lub utraty połączenia sieciowego z serwerem. Wyjątki mogą również wynikać z błędów programistycznych lub nieprawidłowego użycia API. W przeciwieństwie do ludzi w prawdziwym świecie, program musi dokładnie wiedzieć, jak radzić sobie w takich sytuacjach. W tym celu Java ma mechanizm znany jako obsługa wyjątków.Kilka słów o słowach kluczowych
Obsługa wyjątków w Javie opiera się na wykorzystaniu 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ługiwane są wyjątki;
- w końcu — definiuje opcjonalny blok kodu, który, jeśli jest obecny, jest wykonywany niezależnie od wyników bloku try.
- throw - używany do zgłaszania wyjątku;
- throws — używane w sygnaturze metody do ostrzeżenia, że metoda może zgłosić wyjątek.
// This method reads a string from the keyboard
public String input() throws MyException { // Use throws to warn
// that the method may throw a MyException
BufferedReader reader = new BufferedReader(new InputStreamReader(System.in));
String s = null;
// We use a try block to wrap code that might create an exception. In this case,
// the compiler tells us that the readLine() method in the
// BufferedReader class might throw an I/O exception
try {
s = reader.readLine();
// We use a catch block to wrap the code that handles an IOException
} catch (IOException e) {
System.out.println(e.getMessage());
// We close the read stream in the finally block
} finally {
// An exception might occur when we close the stream if, for example, the stream was not open, so we wrap the code in a try block
try {
reader.close();
// Handle exceptions when closing the read stream
} catch (IOException e) {
System.out.println(e.getMessage());
}
}
if (s.equals("")) {
// We've decided that an empty string will prevent our program from working properly. For example, we use the result of this method to call the substring(1, 2) method. Accordingly, we have to interrupt the program by using throw to generate our own MyException exception type.
throw new MyException("The string cannot be empty!");
}
return s;
}
Dlaczego potrzebujemy wyjątków?
Spójrzmy na przykład z prawdziwego świata. Wyobraź sobie, że na odcinku autostrady znajduje się mały most o ograniczonej nośności. Jeśli przejedzie po nim samochód cięższy niż limit mostu, może się on zawalić. Sytuacja kierowcy stałaby się, delikatnie mówiąc, wyjątkowa. Aby tego uniknąć, dział transportu instaluje znaki ostrzegawcze na drodze, zanim coś pójdzie nie tak. Widząc znak ostrzegawczy, kierowca porównuje masę swojego pojazdu z maksymalną masą mostu. Jeśli pojazd jest zbyt ciężki, kierowca wybiera trasę objazdową. Wydział transportu po pierwsze umożliwił kierowcom ciężarówek zmianę trasy w razie potrzeby, po drugie ostrzegał kierowców o niebezpieczeństwach na głównej drodze, a po trzecie ostrzegał kierowców, że w pewnych warunkach nie wolno korzystać z mostu.
Ostrzeganie innych przed „kłopotami”
Jeśli nie planujesz obsługi wyjątków w swojej metodzie, ale chcesz ostrzec innych, że mogą wystąpić wyjątki, użyj słowa kluczowego throws . 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 umożliwia użytkownikom implementację własnej logiki obsługi wyjątków. Po rzutach określamy typy zgłaszanych wyjątków. Zwykle wywodzą się one z klasy wyjątków Javy . Ponieważ Java jest językiem zorientowanym obiektowo, wszystkie wyjątki są obiektami w Javie.
Hierarchia wyjątków
Gdy podczas działania programu wystąpi błąd, JVM tworzy obiekt odpowiedniego typu z hierarchii wyjątków Java — zestawu możliwych wyjątków pochodzących od wspólnego przodka — klasy Throwable . Wyjątkowe sytuacje runtime możemy podzielić na dwie grupy:- Sytuacje, z których program nie może się wycofać i kontynuować normalnej pracy.
- Sytuacje, w których możliwe jest wyzdrowienie.
Tworzenie wyjątku
Podczas uruchamiania programu wyjątki są generowane przez maszynę JVM lub ręcznie za pomocą instrukcji throw . Gdy tak się dzieje, w pamięci tworzony jest obiekt wyjątku, główny przepływ programu zostaje przerwany, a program obsługi wyjątków maszyny JVM próbuje obsłużyć wyjątek.Obsługa wyjątków
W Javie tworzymy bloki kodu, w których przewidujemy potrzebę obsługi wyjątków za pomocą konstrukcji try{}catch , try{}catch{}finally i try{}finally{} . Gdy w bloku try
public class Print {
void print(String s) {
if (s == null) {
throw new NullPointerException("Exception: s is null!");
}
System.out.println("Inside print method: " + 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 handled. The program will continue");
}
finally {
System.out.println("Inside finally block");
}
System.out.println("The program is running...");
System.out.println("-----------------");
}
}
}
Oto wyniki głównej metody :
Inside print method: first step
Inside finally block
The program is running...
-----------------
Exception: s is null!
Exception handled. The program will continue
Inside finally block
The program is running...
-----------------
Inside print method: second step
Inside finally block
The program is running...
-----------------
Final jest zwykle używany do zamykania wszelkich strumieni i zwalniania wszelkich zasobów otwartych/przydzielonych w bloku try . Jednak podczas pisania programu nie zawsze jest możliwe śledzenie zamknięcia wszystkich zasobów. Aby ułatwić nam życie, programiści Javy oferują konstrukcję try-with-resources , która automatycznie zamyka wszystkie zasoby otwarte w bloku try . Nasz pierwszy przykład można przepisać za pomocą 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 ("The string cannot be empty!");
}
return s;
}
Dzięki możliwościom Javy wprowadzonym w wersji 7 możemy również łączyć wychwytywanie heterogenicznych wyjątków w jeden blok, dzięki czemu kod jest bardziej zwarty i czytelny. 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("The string cannot be empty!");
}
} catch (IOException | MyException e) {
System.out.println(e.getMessage());
}
return s;
}
GO TO FULL VERSION