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.
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.
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 =newbyte[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:
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ć.
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.
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.
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.
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.
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ł.
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).
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.
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.
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.
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ć
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.
Odpowiedzi:
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
.źródło
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
źródło
boolean assertionsEnabled = false; assert assertionsEnabled = true;
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.Error
na najwyższym poziomie.Jeśli spojrzysz na listę błędów, zobaczysz, że większość można sobie poradzić. Na przykład
ZipError
podczas odczytu uszkodzonych plików zip.Najczęstszymi błędami są
OutOfMemoryError
iNoClassDefFoundError
, które w większości przypadków są problemami w czasie wykonywania.Na przykład:
może wygenerować błąd,
OutOfMemoryError
ale jest to problem w czasie wykonywania i nie ma powodu do zakończenia programu.NoClassDefFoundError
wystę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ć
Throwable
na najwyższym poziomie i wyświetlić pomocny komunikat o błędzie.źródło
OutOfMemoryError
nie 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ślilength
dane wejściowe są niezaufane, należy je zweryfikować przed wywołaniemnew byte[]
.NoClassDefFoundError
moż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życiajava.util.*
klasy i praktycznie niemożliwe jest programowanie przeciwko niemu. Jeśli opcjonalnie dołączasz zależność, powinieneś użyć,ClassLoader
aby sprawdzić, czy istnieje, co zgłaszaClassNotFoundException
.ZipError
wskazuje, ż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.java.lang.Error
lubjava.lang.Throwable
na 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,String
co wyzwala inną OOM.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:
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ć.
źródło
OutOfMemoryError
i kontynuowanie zamiast szybkiego istnienia jest nierozsądne, ponieważ program znajduje się wtedy w niezdefiniowanym stanie .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.
źródło
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.
źródło
Error
Zazwyczaj nie powinien być złapany , gdyż wskazuje na nieprawidłowy stan, który nigdy nie powinien wystąpić .Ze specyfikacji Java API dla
Error
klasy:Jak wspomina specyfikacja, an
Error
jest generowany tylko w okolicznościach, w których istnieje prawdopodobieństwo, że gdyError
wystą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ładVirtualMachineError
)Chociaż an
Error
jest podklasą,Throwable
co oznacza, że może zostać przechwycony przeztry-catch
klauzulę, ale prawdopodobnie nie jest naprawdę potrzebny, ponieważ aplikacja będzie w nienormalnym stanie, gdyError
zostanie 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 .
źródło
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.
źródło
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):
źródło
Error
s.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).
źródło
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:
źródło
całkiem wygodne jest przechwycenie java.lang.AssertionError w środowisku testowym ...
źródło
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.
źródło
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.
źródło
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ć
źródło
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.
źródło