Kiedy złapać java.lang.Error?


Odpowiedzi:


101

Generalnie nigdy.

Czasami jednak trzeba wyłapać określone błędy.

Jeśli piszesz kod framework-ish (ładowanie klas stron trzecich), rozsądnie może być przechwycenie LinkageError(brak definicji klasy, niezadowalający link, niezgodna zmiana klasy).

Widziałem też kilka głupich podklas rzucających kod firm trzecich Error, więc będziesz musiał sobie z nimi poradzić.

Nawiasem mówiąc, nie jestem pewien, czy nie da się wyzdrowieć OutOfMemoryError.


3
To, co musiałem zrobić dokładnie, aby załadować biblioteki DLL, które zakończyłyby się niepowodzeniem, gdyby nie były poprawnie skonfigurowane. Nie jest to błąd krytyczny w przypadku tej aplikacji.
Mario Ortegón,

7
Czasami ma sens wychwycenie OutOfMemoryError - na przykład podczas tworzenia dużych list tablicowych.
SpaceTrucker,

3
@SpaceTrucker: czy to podejście działa dobrze w aplikacjach wielowątkowych, czy też istnieje znaczne ryzyko, że mniejsze alokacje w innych wątkach zawiodą z tego powodu? … Prawdopodobnie tylko wtedy, gdy twoje tablice były na tyle małe, że można je było przydzielić, ale nie pozostawiły nic dla nikogo innego.
PJTraill

@PJTraill Nie jestem tego pewien. Wymagałoby to kilku rzeczywistych próbek statystycznych. Myślałem, że widziałem taki kod, ale nie pamiętam, gdzie to było.
SpaceTrucker

51

Nigdy. Nigdy nie możesz być pewien, że aplikacja będzie w stanie wykonać następny wiersz kodu. Jeśli otrzymasz OutOfMemoryError, nie masz gwarancji, że będziesz w stanie cokolwiek zrobić niezawodnie . Catch RuntimeException i zaznaczone Exceptions, ale nigdy Errors.

http://pmd.sourceforge.net/rules/strictexception.html


27
Nigdy nie mów nigdy. mamy kod testowy, który wykonuje „assert false”; następnie przechwytuje AssertionError, aby upewnić się, że flaga -ea jest ustawiona. Poza tym ... tak, prawdopodobnie nigdy ;-)
Outlaw Programmer

3
A co z aplikacją serwera, która przekazuje żądania do wątków roboczych. Czy nie ma sensu łapanie Throwable'a na wątku roboczym, aby wyłapać wszelkie błędy, a przynajmniej spróbować zarejestrować, co poszło nie tak?
Leigh,

11
Nigdy ... z wyjątkiem sytuacji, gdy absolutnie tego potrzebujesz. Nigdy nie jest mocnym słowem i zawsze są wyjątki od zasad. Jeśli tworzysz framework, nie jest tak mało prawdopodobne, że będziesz musiał wychwycić i obsłużyć pewne błędy, nawet jeśli jest to tylko rejestracja.
Robin

A co z błędami, np. NoSuchMethodError pochodzącymi z metod bibliotecznych innych firm?
ha9u63ar

@OutlawProgrammer Tak dla przypomnienia, są inne sposoby na wykonanie tego samego testu:boolean assertionsEnabled = false; assert assertionsEnabled = true;
shmosel

16

Generalnie zawsze powinieneś łapać java.lang.Error i zapisać w dzienniku lub wyświetlić użytkownikowi. Pracuję jako pomoc techniczna i codziennie widzę, że programiści nie są w stanie powiedzieć, co się stało w programie.

Jeśli masz wątek demona, musisz uniemożliwić jego zakończenie. W innych przypadkach Twoja aplikacja będzie działać poprawnie.

Powinieneś łapać tylko java.lang.Errorna najwyższym poziomie.

Jeśli spojrzysz na listę błędów, zobaczysz, że większość można sobie poradzić. Na przykład ZipErrorpodczas odczytu uszkodzonych plików zip.

Najczęstszymi błędami są OutOfMemoryErrori NoClassDefFoundError, które w większości przypadków są problemami w czasie wykonywania.

Na przykład:

int length = Integer.parseInt(xyz);
byte[] buffer = new byte[length];

może wygenerować błąd, OutOfMemoryErrorale jest to problem w czasie wykonywania i nie ma powodu do zakończenia programu.

NoClassDefFoundErrorwystępują głównie wtedy, gdy nie ma biblioteki lub pracujesz z inną wersją Java. Jeśli jest to opcjonalna część programu, nie należy go przerywać.

Mogę podać o wiele więcej przykładów, dlaczego dobrze jest złapać Throwablena najwyższym poziomie i wyświetlić pomocny komunikat o błędzie.


podejrzewałbym, że w takich przypadkach lepiej jest zawieść demona odpowiednimi alertami, a potem mieć możliwość, że pozostanie przy życiu jako duch eteryczny na nieudanym jvm, gdzie może dać fałszywy pretekst, że naprawdę żyje i coś robi
Andrew Norman

OutOfMemoryErrornie jest błędem w czasie wykonywania, nie ma gwarancji, że aplikacja będzie w stanie go naprawić. Jeśli masz szczęście, możesz dostać OOM, new byte[largeNumber]ale jeśli ta alokacja nie wystarczy, aby spowodować OOM, może zostać wyzwolona w następnej linii lub następnym wątku. Jest to problem w czasie wykonywania, ponieważ jeśli lengthdane wejściowe są niezaufane, należy je zweryfikować przed wywołaniem new byte[].
Jeeyoung Kim

NoClassDefFoundErrormoże wystąpić wszędzie , ponieważ jest wywoływana, gdy skompilowany kod java nie może znaleźć klasy. Jeśli twój JDK jest źle skonfigurowany, może to spowodować próbę użycia java.util.*klasy i praktycznie niemożliwe jest programowanie przeciwko niemu. Jeśli opcjonalnie dołączasz zależność, powinieneś użyć, ClassLoaderaby sprawdzić, czy istnieje, co zgłasza ClassNotFoundException.
Jeeyoung Kim

1
ZipErrorwskazuje, że plik jar zawierający klasy jest uszkodzonym plikiem ZIP. Jest to dość poważny problem i na tym etapie nie można ufać żadnemu kodowi, który zostanie wykonany, a próba „odzyskania” go z tego powodu byłaby nieodpowiedzialna.
Jeeyoung Kim

2
Ogólnie rzecz biorąc, pomocne może być złapanie java.lang.Errorlub java.lang.Throwablena najwyższym poziomie i próba zrobienia czegoś z tym - powiedzmy zarejestruj komunikat o błędzie. Ale w tym momencie nie ma gwarancji, że zostanie to wykonane. Jeśli Twoja maszyna JVM znajduje się w fazie OOM, próba zarejestrowania może przydzielić więcej adresów, Stringco wyzwala inną OOM.
Jeeyoung Kim

15

W środowisku wielowątkowym najczęściej chcesz to złapać! Kiedy go złapiesz, zaloguj się i zamknij całą aplikację! Jeśli tego nie zrobisz, wątek, który może wykonywać jakąś kluczową część, byłby martwy, a reszta aplikacji pomyśli, że wszystko jest w porządku. Z tego może zdarzyć się wiele niechcianych sytuacji. Najmniejszym problemem jest to, że nie byłoby łatwo znaleźć źródła problemu, gdyby inne wątki zaczęły zgłaszać wyjątki z powodu niedziałającego jednego wątku.

Na przykład zwykle pętla powinna wyglądać następująco:

try {
   while (shouldRun()) {
       doSomething();
   }
}
catch (Throwable t) {
   log(t);
   stop();
   System.exit(1);
}

Nawet w niektórych przypadkach chciałbyś inaczej obsługiwać różne błędy, na przykład w OutOfMemoryError byłbyś w stanie regularnie zamykać aplikację (może nawet zwolnić trochę pamięci i kontynuować), w innych niewiele można zrobić.


1
Łapanie OutOfMemoryError i kontynuowanie zamiast szybkiego istnienia jest nierozsądne, ponieważ program znajduje się wtedy w niezdefiniowanym stanie .
Raedwald

1
wywoływanie systemu, wyjście po złapaniu przedmiotu do rzucania powoduje niezamierzone konsekwencje zabicia wszystkiego, co działa na JVM, a nie tylko danej aplikacji. Zwykle nie jest to dobra praktyka w przypadku aplikacji internetowych, które mogą być hostowane na serwerze aplikacji z innymi aplikacjami internetowymi (nie wspominając o tym, że wpłynie to na sam serwer aplikacji).
Andrew Norman

9

Bardzo rzadko.

Powiedziałbym tylko na najwyższym poziomie wątku, aby PRÓBOWAĆ wysłać wiadomość z przyczyną umierania wątku.

Jeśli pracujesz we frameworku, który robi to za ciebie, zostaw to frameworkowi.


6

Prawie nigdy. Błędy są zaprojektowane tak, aby były problemami, z którymi aplikacje na ogół nie mogą nic zrobić. Jedynym wyjątkiem może być obsługa prezentacji błędu, ale nawet to może nie przebiegać zgodnie z planem w zależności od błędu.


6

ErrorZazwyczaj nie powinien być złapany , gdyż wskazuje na nieprawidłowy stan, który nigdy nie powinien wystąpić .

Ze specyfikacji Java API dla Errorklasy:

Jest Errorpodklasą tego, Throwable co wskazuje na poważne problemy, których rozsądna aplikacja nie powinna próbować wychwycić. Większość takich błędów to nieprawidłowe warunki. […]

Metoda nie musi deklarować w swojej klauzuli throws żadnych podklas Error, które mogą zostać wyrzucone podczas wykonywania metody, ale nie zostaną przechwycone, ponieważ te błędy są nienormalnymi warunkami, które nigdy nie powinny wystąpić.

Jak wspomina specyfikacja, an Errorjest generowany tylko w okolicznościach, w których istnieje prawdopodobieństwo, że gdy Errorwystąpi, aplikacja może zrobić bardzo niewiele, aw niektórych okolicznościach sama wirtualna maszyna Javy może znajdować się w niestabilnym stanie (na przykład VirtualMachineError)

Chociaż an Errorjest podklasą, Throwableco oznacza, że ​​może zostać przechwycony przez try-catchklauzulę, ale prawdopodobnie nie jest naprawdę potrzebny, ponieważ aplikacja będzie w nienormalnym stanie, gdy Errorzostanie wyrzucona przez JVM.

Jest też krótki odcinek na ten temat w rozdziale 11.5 hierarchii Wyjątek od języka Java Specification, 2nd Edition .


6

Jeśli jesteś na tyle szalony, że tworzysz nową strukturę testów jednostkowych, program uruchamiający testy prawdopodobnie będzie musiał przechwycić błąd java.lang.AssertionError generowany przez dowolne przypadki testowe.

W przeciwnym razie zobacz inne odpowiedzi.


5

I jest kilka innych przypadków, w których jeśli złapiesz błąd, musisz go ponownie zgłosić . Na przykład ThreadDeath nigdy nie powinien zostać przechwycony, może to spowodować duży problem, jeśli złapiesz go w zamkniętym środowisku (np. Serwerze aplikacji):

Aplikacja powinna przechwytywać wystąpienia tej klasy tylko wtedy, gdy musi zostać wyczyszczona po asynchronicznym zakończeniu. Jeśli ThreadDeath zostanie przechwycony przez metodę, ważne jest, aby został ponownie wyrzucony, aby wątek faktycznie umarł.


2
Co właściwie nie stanowi problemu, ponieważ po prostu nie łapiesz Errors.
Bombe

4

Bardzo, bardzo rzadko.

Zrobiłem to tylko dla jednego, bardzo konkretnego, znanego przypadku. Na przykład błąd java.lang.UnsatisfiedLinkError może zostać zgłoszony, jeśli dwie niezależne klasy ClassLoader ładują tę samą bibliotekę DLL. (Zgadzam się, że powinienem przenieść JAR do współdzielonego modułu ładującego)

Ale najczęstszym przypadkiem jest to, że trzeba było się zalogować, aby wiedzieć, co się stało, gdy użytkownik złożył skargę. Chcesz wiadomość lub wyskakujące okienko dla użytkownika, a nie cicho martwe.

Nawet programista w C / C ++, wyskakuje błąd i mówi coś, czego ludzie nie rozumieją, zanim się zakończy (np. Awaria pamięci).


3

W aplikacji na Androida łapię błąd java.lang.VerifyError . Biblioteka, której używam, nie będzie działać na urządzeniach ze starą wersją systemu operacyjnego i kod biblioteki będzie generował taki błąd. Mogłem oczywiście uniknąć błędu, sprawdzając wersję systemu operacyjnego w czasie wykonywania, ale:

  • Najstarszy obsługiwany pakiet SDK może w przyszłości ulec zmianie dla określonej biblioteki
  • Blok błędu try-catch jest częścią większego mechanizmu cofania. Niektóre konkretne urządzenia, mimo że mają obsługiwać bibliotekę, rzucają wyjątki. Łapię VerifyError i wszystkie wyjątki, aby użyć rozwiązania awaryjnego.

3

całkiem wygodne jest przechwycenie java.lang.AssertionError w środowisku testowym ...


Jaką wartość próbujesz dodać?
lpapp

dodanie wartości zestawu testów nie przerywa pracy
Jono,

2

W idealnym przypadku nie powinniśmy obsługiwać / wychwytywać błędów. Ale mogą być przypadki, w których musimy to zrobić, w oparciu o wymagania dotyczące frameworka lub aplikacji. Powiedzmy, że mam demona XML Parser, który implementuje Parser DOM, który zużywa więcej pamięci. Jeśli istnieje wymóg, taki jak Parser, wątek nie powinien być przerywany , gdy otrzyma OutOfMemoryError , zamiast tego powinien go obsłużyć i wysłać wiadomość / e-mail do administratora aplikacji / frameworka.


1

Idealnie byłoby, gdybyśmy nigdy nie wychwycili błędu w naszej aplikacji Java, ponieważ jest to stan nienormalny. Aplikacja byłaby w nienormalnym stanie i mogłaby spowodować samochód lub dać bardzo zły wynik.


1

Może być właściwe wychwycenie błędu w testach jednostkowych, które sprawdzają, czy potwierdzono. Jeśli ktoś wyłączy potwierdzenia lub w inny sposób usunie potwierdzenie, które chciałbyś wiedzieć


1

Występuje błąd, gdy maszyna JVM nie działa zgodnie z oczekiwaniami lub jest na skraju. Jeśli złapiesz błąd, nie ma gwarancji, że blok catch będzie działał, a tym bardziej, że będzie działał do końca.

Zależy to również od uruchomionego komputera, aktualnego stanu pamięci, więc nie ma możliwości testowania, próbowania i dawania z siebie wszystkiego. Będziesz miał tylko szybki wynik.

Zmniejszysz także czytelność swojego kodu.

Korzystając z naszej strony potwierdzasz, że przeczytałeś(-aś) i rozumiesz nasze zasady używania plików cookie i zasady ochrony prywatności.
Licensed under cc by-sa 3.0 with attribution required.