Jak prawidłowo obsługiwać wyjątki Java?

Jak prawidłowo obsługiwać wyjątki Java?

Jako początkujący programista koncepcja Obsługa wyjątków może być trudno owinąć głowę. Nie chodzi o to, że sama koncepcja jest trudna, ale terminologia może sprawić, że wydaje się bardziej zaawansowana niż jest. Jest to tak potężna funkcja, że ​​jest podatna na niewłaściwe użycie i nadużycia.





W tym artykule dowiesz się, czym są wyjątki, dlaczego są ważne, jak z nich korzystać oraz dowiesz się, jakich błędów należy unikać. Większość współczesnych języków ma pewien rodzaj obsługi wyjątków, więc jeśli kiedykolwiek przejdziesz z Javy , możesz zabrać ze sobą większość tych wskazówek.





Zrozumienie wyjątków Java

W Javie wyjątek to obiekt, który wskazuje, że podczas działania aplikacji wystąpiło coś nienormalnego (lub „wyjątkowego”). Takimi wyjątkami są rzucony , co zasadniczo oznacza, że ​​tworzony jest obiekt wyjątku (podobnie jak „podnoszone” są błędy).





Piękno polega na tym, że możesz łapać zgłoszone wyjątki, co pozwala poradzić sobie z nienormalnym stanem i umożliwić aplikacji kontynuowanie działania, tak jakby nic nie poszło nie tak. Na przykład, podczas gdy pusty wskaźnik w C może spowodować awarię aplikacji, Java pozwala rzucać i łapać

NullPointerException

s zanim zmienna o wartości null ma szansę spowodować awarię.



Pamiętaj, że wyjątek to tylko obiekt, ale z jedną ważną cechą: musi być rozszerzony od

Exception

klasa lub dowolna podklasa





Exception

. Chociaż Java ma wszystkie rodzaje wbudowanych wyjątków, możesz również utworzyć własne, jeśli chcesz. Niektórzy najczęstsze wyjątki Java włączać:

  • NullPointerException
  • NumberFormatException
  • IllegalArgumentException
  • RuntimeException
  • IllegalStateException

Co się stanie, gdy zgłosisz wyjątek?





Po pierwsze, Java sprawdza w metodzie bezpośredniej, czy istnieje kod, który obsługuje wyrzucony przez Ciebie rodzaj wyjątku. Jeśli uchwyt nie istnieje, sprawdza metodę, która wywołała bieżącą metodę, aby sprawdzić, czy istnieje tam uchwyt. Jeśli nie, sprawdza metodę, która wywołała że metoda, a następnie następna metoda itd. Jeśli wyjątek nie zostanie przechwycony, aplikacja drukuje ślad stosu, a następnie ulega awarii. (W rzeczywistości jest to bardziej zniuansowane niż zwykłe awarie, ale to zaawansowany temat wykraczający poza zakres tego artykułu).

DO Ślad stosu to lista wszystkich metod, przez które przeszła Java podczas szukania obsługi wyjątków. Oto jak wygląda ślad stosu:

Exception in thread 'main' java.lang.NullPointerException
at com.example.myproject.Book.getTitle(Book.java:16)
at com.example.myproject.Author.getBookTitles(Author.java:25)
at com.example.myproject.Bootstrap.main(Bootstrap.java:14)

Wiele możemy z tego wyciągnąć. Po pierwsze, zgłoszony wyjątek to

NullPointerException

. Miało to miejsce w

getTitle()

metoda w wierszu 16 Book.java. Ta metoda została wywołana z

getBookTitles()

w wierszu 25 Author.java. To metoda została wywołana z

main()

w wierszu 14 Bootstrap.java. Jak widać, znajomość tego wszystkiego ułatwia debugowanie.

Ale znowu, prawdziwą zaletą wyjątków jest to, że możesz „obsłużyć” nienormalny stan, przechwytując wyjątek, ustawiając wszystko w porządku i wznawiając aplikację bez awarii.

Używanie wyjątków Java w kodzie

Powiedzmy, że masz

someMethod()

który pobiera liczbę całkowitą i wykonuje pewną logikę, która może się zepsuć, jeśli liczba całkowita jest mniejsza niż 0 lub większa niż 100. Może to być dobre miejsce na zgłoszenie wyjątku:

gdzie znaleźć imei na iPhonie?
public void someMethod(int value) {
if (value 100) {
throw new
IllegalArgumentException

Aby złapać ten wyjątek, musisz udać się dokąd

someMethod()

nazywa się i użyj blok try-catch :

public void callingMethod() {
try {
someMethod(200);
someOtherMethod();
} catch (IllegalArgumentException e) {
// handle the exception in here
}
// ...
}

Wszystko w obrębie próbować blok będzie wykonywany w kolejności, dopóki nie zostanie zgłoszony wyjątek. Jak tylko zostanie zgłoszony wyjątek, wszystkie kolejne instrukcje są pomijane, a logika aplikacji natychmiast przeskakuje do łapać blok.

W naszym przykładzie wpisujemy blok try i natychmiast wywołujemy

someMethod()

. Ponieważ 200 nie mieści się w przedziale od 0 do 100, a

IllegalArgumentException

Jest rzucony. To natychmiast kończy wykonanie

someMethod()

, pomija resztę logiki w bloku try (

someOtherMethod()

nigdy nie jest wywoływana) i wznawia wykonywanie w bloku catch.

Co by się stało, gdybyśmy zadzwonili

someMethod(50)

zamiast? ten

IllegalArgumentException

nigdy nie zostanie rzucony.

someMethod()

wykonałby się normalnie. Blok try wykonałby się normalnie, wywołując

someOtherMethod()

po zakończeniu someMethod(). Kiedy

someOtherMethod()

kończy się, blok catch zostanie pominięty i

callingMethod()

będzie kontynuowane.

Zauważ, że możesz mieć wiele bloków catch na blok try:

public void callingMethod() {
try {
someMethod(200);
someOtherMethod();
} catch (IllegalArgumentException e) {
// handle the exception in here
} catch (NullPointerException e) {
// handle the exception in here
}
// ...
}

Należy również pamiętać, że opcjonalny wreszcie istnieje również blok:

public void method() {
try {
// ...
} catch (Exception e) {
// ...
} finally {
// ...
}
}

Kod w bloku last to zawsze wykonywane bez względu na wszystko. Jeśli masz instrukcję return w bloku try, blok finally jest wykonywany przed powrotem z metody. Jeśli zgłosisz inny wyjątek w bloku catch, blok finally zostanie wykonany przed zgłoszeniem wyjątku.

Powinieneś użyć bloku finally, gdy masz obiekty, które muszą zostać oczyszczone przed zakończeniem metody. Na przykład, jeśli otworzyłeś plik w bloku try, a później zgłosiłeś wyjątek, blok finally umożliwia zamknięcie pliku przed opuszczeniem metody.

Zauważ, że możesz mieć Last Block bez catch:

public void method() {
try {
// ...
} finally {
// ...
}
}

Pozwala to wykonać wszelkie niezbędne porządki, jednocześnie zezwalając na zgłoszone wyjątki na propagację stosu wywołań metody (tj. Nie chcesz tutaj obsługiwać wyjątku, ale nadal musisz najpierw wyczyścić).

Sprawdzone i niesprawdzone wyjątki w Javie

W przeciwieństwie do większości języków, Java rozróżnia sprawdzone wyjątki oraz niesprawdzone wyjątki (np. C# ma tylko niesprawdzone wyjątki). Sprawdzony wyjątek musi zostać przechwycone w metodzie, w której zgłoszony jest wyjątek, w przeciwnym razie kod nie zostanie skompilowany.

Aby utworzyć zaznaczony wyjątek, rozszerz z

Exception

. Aby utworzyć niesprawdzony wyjątek, rozszerz z

RuntimeException

.

Każda metoda, która zgłasza sprawdzony wyjątek, musi oznaczyć to w podpisie metody przy użyciu rzuty słowo kluczowe. Ponieważ wbudowana jest Java

IOException

jest sprawdzonym wyjątkiem, poniższy kod nie skompiluje się:

public void wontCompile() {
// ...
if (someCondition) {
throw new IOException();
}
// ...
}

Musisz najpierw zadeklarować, że zgłasza sprawdzony wyjątek:

public void willCompile() throws IOException {
// ...
if (someCondition) {
throw new IOException();
}
// ...
}

Należy zauważyć, że metodę można zadeklarować jako zgłaszającą wyjątek, ale nigdy nie zgłaszać wyjątku. Mimo to wyjątek nadal będzie musiał zostać przechwycony, w przeciwnym razie kod się nie skompiluje.

Kiedy należy używać zaznaczonych lub niesprawdzonych wyjątków?

Oficjalna dokumentacja Java ma strona na to pytanie . Podsumowuje różnicę za pomocą zwięzłej zasady: „Jeśli można racjonalnie oczekiwać, że klient odzyska sprawność po wyjątku, uczyń go sprawdzonym wyjątkiem. Jeśli klient nie może nic zrobić, aby odzyskać dane z wyjątku, uczyń go niesprawdzonym wyjątkiem.'

Ale ta wytyczna może być nieaktualna. Z jednej strony sprawdzone wyjątki dają bardziej niezawodny kod . Z drugiej strony, żaden inny język nie sprawdza wyjątków w taki sam sposób jak Java, co pokazuje dwie rzeczy: po pierwsze, funkcja nie jest wystarczająco użyteczna, aby inne języki ją ukradła, a po drugie, absolutnie można bez nich żyć. Ponadto zaznaczone wyjątki nie działają dobrze z wyrażeniami lambda wprowadzonymi w Javie 8.

Wskazówki dotyczące używania wyjątków Java

Wyjątki są przydatne, ale łatwo je nadużywać i nadużywać. Oto kilka wskazówek i najlepszych praktyk, które pomogą Ci uniknąć bałaganu.

  • Preferuj określone wyjątki od wyjątków ogólnych. Użyj |__+_| ponad |__+_| jeśli to możliwe, w przeciwnym razie użyj |_+_| ponad |__+_| kiedy możliwe.
  • Nigdy nie łap |_+_| ! |__+_| klasa faktycznie rozszerza |_+_| , a blok catch faktycznie działa z |_+_| lub dowolna klasa, która rozszerza Throwable. Jednak |_+_| klasa również rozszerza |_+_| i nigdy nie chcesz złapać |_+_| ponieważ |__+_| s wskazują na poważne, nieodwracalne problemy.
  • Nigdy nie łap |_+_| ! |_+_| rozciąga |__+_| , więc każdy blok, który przechwytuje |_+_| złapie również |_+_| i jest to bardzo ważny wyjątek, z którym nie chcesz zadzierać (szczególnie w aplikacjach wielowątkowych), chyba że wiesz, co robisz. Jeśli nie wiesz, który wyjątek przechwycić zamiast tego, rozważ nie złapanie niczego.
  • Użyj opisowych komunikatów, aby ułatwić debugowanie. Kiedy zgłaszasz wyjątek, możesz podać |_+_| wiadomość jako argument. Dostęp do tej wiadomości można uzyskać w bloku catch za pomocą |_+_| metody, ale jeśli wyjątek nigdy nie zostanie przechwycony, komunikat pojawi się również jako część śladu stosu.
  • Staraj się nie łapać i nie ignorować wyjątków. Aby obejść niedogodność sprawdzanych wyjątków, wielu początkujących i leniwych programistów utworzy blok catch, ale pozostawi go pusty. Zły! Zawsze obsługuj to z wdziękiem, ale jeśli nie możesz, wydrukuj przynajmniej ślad stosu, aby wiedzieć, że wyjątek został zgłoszony. Możesz to zrobić za pomocą |_+_| metoda.
  • Uważaj na nadużywanie wyjątków. Kiedy masz młotek, wszystko wygląda jak gwóźdź. Kiedy po raz pierwszy dowiesz się o wyjątkach, możesz poczuć się zobowiązany do przekształcenia wszystkiego w wyjątek... do momentu, w którym większość przepływu kontroli aplikacji sprowadza się do obsługi wyjątków. Pamiętaj, wyjątki są przeznaczone dla „wyjątkowych” zdarzeń!

Teraz powinieneś być wystarczająco wygodny z wyjątkami, aby zrozumieć, czym one są, dlaczego są używane i jak włączyć je do własnego kodu. Jeśli nie rozumiesz w pełni koncepcji, to w porządku! Zajęło mi trochę czasu, zanim „kliknęło” w mojej głowie, więc nie musisz się spieszyć . Nie spiesz się.

Masz pytania? Czy znasz jakieś inne wskazówki dotyczące wyjątków, które przegapiłem? Podziel się nimi w komentarzach poniżej!

Udział Udział Ćwierkać E-mail Jak utworzyć diagram przepływu danych w celu wizualizacji danych dowolnego projektu?

Diagramy przepływu danych (DFD) dowolnego procesu pomagają zrozumieć, w jaki sposób dane przepływają ze źródła do miejsca docelowego. Oto jak to stworzyć!

Czytaj dalej
Powiązane tematy
  • Programowanie
  • Jawa
O autorze Joel Lee(1524 opublikowanych artykułów)

Joel Lee jest redaktorem naczelnym MakeUseOf od 2018 roku. Posiada licencjat. w informatyce i ponad 9-letnie doświadczenie zawodowe w pisaniu i redagowaniu.

jak tworzyć muzykę za darmo
Więcej od Joela Lee

Zapisz się do naszego newslettera

Dołącz do naszego newslettera, aby otrzymywać porady techniczne, recenzje, bezpłatne e-booki i ekskluzywne oferty!

Kliknij tutaj, aby zasubskrybować