Czy łowienie jest złą praktyką Throwable
?
Na przykład coś takiego:
try {
// Some code
} catch(Throwable e) {
// handle the exception
}
Czy to zła praktyka, czy też powinniśmy być jak najbardziej konkretni?
java
exception-handling
throwable
ktulinho
źródło
źródło
Odpowiedzi:
Musisz być jak najbardziej konkretny. W przeciwnym razie nieprzewidziane błędy mogą zniknąć w ten sposób.
Poza tym
Throwable
okładkiError
też i to zwykle nie ma sensu . Nie chcesz tego złapać / obsłużyć, chcesz, aby twój program natychmiast umarł, abyś mógł go poprawnie naprawić.źródło
To jest zły pomysł. W rzeczywistości nawet łowienie
Exception
jest zwykle złym pomysłem. Rozważmy przykład:Teraz powiedzmy, że getUserInput () blokuje się na chwilę, a inny wątek zatrzymuje twój wątek w najgorszy możliwy sposób (wywołuje thread.stop ()). Twój blok catch wykryje
ThreadDeath
błąd. To jest bardzo złe. Zachowanie kodu po przechwyceniu tego wyjątku jest w dużej mierze niezdefiniowane.Podobny problem występuje przy przechwytywaniu wyjątku. Może
getUserInput()
nie powiodło się z powodu wyjątku InterruptException lub wyjątku odmowy uprawnień podczas próby rejestrowania wyników lub wszelkiego rodzaju innych niepowodzeń. Nie masz pojęcia, co poszło nie tak, ponieważ z tego powodu nie masz również pojęcia, jak rozwiązać problem.Masz trzy lepsze opcje:
1 - Wyłap dokładnie wyjątek (y), z którymi umiesz sobie poradzić:
2 - Ponownie wyświetl każdy wyjątek, na który napotkasz i nie wiesz, jak sobie poradzić:
3 - Użyj końcowego bloku, aby nie pamiętać o ponownym rzucie:
źródło
throw new Exception("Some additional info, eg. userId " + userId, e);
. Zostanie to zarejestrowane w jednym ładnym wyjątku z 10 przyczynami.Należy również pamiętać, że złapanie
Throwable
można również złapać,InterruptedException
co wymaga specjalnego traktowania. Aby uzyskać więcej informacji, zobacz Radzenie sobie z InterruptedException .Jeśli chcesz złapać tylko niezaznaczone wyjątki, możesz również rozważyć ten wzorzec
W ten sposób, gdy zmodyfikujesz kod i dodasz wywołanie metody, które może zgłosić zaznaczony wyjątek, kompilator przypomni Ci o tym, a następnie będziesz mógł zdecydować, co zrobić w tym przypadku.
źródło
bezpośrednio z javadoc klasy Error (która zaleca, aby ich nie łapać):
źródło
Nie jest to zła praktyka, jeśli absolutnie nie można wyrzucić wyjątku z metody.
To zła praktyka, jeśli naprawdę nie możesz sobie poradzić z wyjątkiem. Lepiej jest dodać „throws” do sygnatury metody niż po prostu złapać i ponownie rzucić lub, co gorsza, zawinąć ją w RuntimeException i ponownie wyrzucić.
źródło
Throwable
instancji - np. W przypadku niestandardowego rejestrowania wyjątków.Łapanie Throwable jest czasami konieczne, jeśli używasz bibliotek, które z nadmiernym entuzjazmem zgłaszają błędy, w przeciwnym razie twoja biblioteka może zabić twoją aplikację.
Jednak w takich okolicznościach najlepiej byłoby określić tylko konkretne błędy generowane przez bibliotekę, a nie wszystkie Throwables.
źródło
Throwable to podstawowa klasa dla wszystkich klas, którą można rzucić (nie tylko wyjątki). Niewiele możesz zrobić, jeśli złapiesz OutOfMemoryError lub KernelError (zobacz Kiedy przechwycić java.lang.Error? )
wyłapywanie wyjątków powinno wystarczyć.
źródło
zależy to od twojej logiki lub być bardziej szczegółowym od twoich opcji / możliwości. Jeśli jest jakiś wyjątek, na który możesz zareagować w znaczący sposób, możesz go najpierw złapać i zrobić.
Jeśli nie ma i jesteś pewien, że zrobisz to samo dla wszystkich wyjątków i błędów (na przykład wyjście z komunikatem o błędzie), to złapanie przedmiotu rzucanego nie jest problemem.
Zwykle pierwszy przypadek jest prawidłowy i nie złapiesz przedmiotu do rzucania. Ale wciąż jest wiele przypadków, w których złapanie działa dobrze.
źródło
Chociaż jest to opisywane jako bardzo zła praktyka, czasami możesz znaleźć rzadkie przypadki, że nie tylko użyteczne, ale także obowiązkowe. Oto dwa przykłady.
W aplikacji internetowej, w której musisz pokazać użytkownikowi pełną stronę błędu. Ten kod zapewnia, że tak się stanie, ponieważ jest on
try/catch
obszerny wokół wszystkich uchwytów żądań (serwletów, akcji rozpórek lub dowolnego kontrolera ...)}
Jako inny przykład rozważmy klasę usług, która obsługuje transfer środków. Ta metoda zwraca wartość,
TransferReceipt
jeśli transfer został wykonany lubNULL
nie mógł.Teraz obrazując, otrzymujesz
List
przelewy środków od użytkownika i musisz skorzystać z powyższej usługi, aby wykonać je wszystkie.Ale co się stanie, jeśli zdarzy się jakikolwiek wyjątek? Nie powinieneś przerywać, ponieważ jeden transfer mógł się udać, a drugi nie, powinieneś kontynuować przez wszystkich użytkowników
List
i pokazywać wynik dla każdego transferu. Więc kończysz z tym kodem.Możesz przeglądać wiele projektów open source, aby zobaczyć, że
throwable
jest on naprawdę buforowany i obsługiwany. Na przykład o to poszukiwanietomcat
,struts2
orazprimefaces
:https://github.com/apache/tomcat/search?utf8=%E2%9C%93&q=catch%28Throwable https://github.com/apache/struts/search?utf8=%E2%9C%93&q=catch % 28Throwable https://github.com/primefaces/primefaces/search?utf8=%E2%9C%93&q=catch%28Throwable
źródło
throwable
, o co chodzi w tym pytaniuPytanie jest trochę niejasne; pytasz „czy można złapać
Throwable
”, czy „czy można złapaćThrowable
i nic nie robić”? Wiele osób odpowiedziało na to drugie pytanie, ale to kwestia poboczna; W 99% przypadków nie należy „konsumować” ani odrzucać wyjątku, niezależnie od tego, czy jest on łapany,Throwable
czyIOException
czy cokolwiek innego.Jeśli propagujesz wyjątek, odpowiedź (podobnie jak odpowiedź na wiele pytań) brzmi „to zależy”. To zależy od tego, co robisz z wyjątkiem - dlaczego to łapiesz.
Dobrym przykładem tego, dlaczego chcesz przechwycić,
Throwable
jest zapewnienie pewnego rodzaju czyszczenia, jeśli wystąpi jakikolwiek błąd. Na przykład w JDBC, jeśli wystąpi błąd podczas transakcji, chcesz wycofać transakcję:Zauważ, że wyjątek nie jest odrzucany, ale propagowany.
Ale ogólnie rzecz biorąc, łapanie,
Throwable
ponieważ nie masz powodu i jesteś zbyt leniwy, aby zobaczyć, które konkretne wyjątki są rzucane, jest kiepską formą i złym pomysłem.źródło
Ogólnie rzecz biorąc, chcesz uniknąć łapania
Error
s, ale przychodzą mi do głowy (przynajmniej) dwa konkretne przypadki, w których jest to właściwe:AssertionError
co w innym przypadku jest nieszkodliwe.źródło
Jeśli używamy przedmiotu miotanego , obejmuje on również błąd i to wszystko.
Przykład.
}
Wynik:
źródło
Rzut jest superklasą wszystkich błędów i wyjątków. Jeśli użyjesz Throwable w klauzuli catch, nie tylko wyłapie wszystkie wyjątki, ale także wyłapie wszystkie błędy. JVM generuje błędy w celu wskazania poważnych problemów, które nie są przeznaczone do obsługi przez aplikację. Typowe przykłady to OutOfMemoryError lub StackOverflowError. Obie są spowodowane sytuacjami, które są poza kontrolą aplikacji i nie można ich obsłużyć. Więc nie powinieneś łapać Throwables, chyba że jesteś całkiem pewien, że będzie to tylko wyjątek znajdujący się w Throwable.
źródło
Chociaż ogólnie złą praktyką jest łapanie Throwable (jak wyjaśniono w licznych odpowiedziach na to pytanie), scenariusze, w których łapanie
Throwable
jest przydatne, są dość powszechne. Pozwólcie, że wyjaśnię jeden taki przypadek, który wykorzystuję w pracy, na uproszczonym przykładzie.Rozważ metodę, która polega na dodaniu dwóch liczb, a po pomyślnym dodaniu wysyła alert e-mail do określonych osób. Załóżmy, że zwracany numer jest ważny i używany przez metodę wywołującą.
Kod służący do wysyłania alertów e-mailowych odczytuje wiele konfiguracji systemu, dlatego z tego bloku kodu może być wyrzucanych wiele wyjątków. Ale nie chcemy, aby jakikolwiek wyjątek napotkany podczas wysyłania alertu był propagowany do metody wywołującej, ponieważ ta metoda jest po prostu związana z sumą dwóch wartości całkowitych, które zapewnia. W związku z tym kod do wysyłania alertów e-mailowych jest umieszczony w
try-catch
bloku, w którymThrowable
jest przechwytywany, a wszelkie wyjątki są jedynie rejestrowane, co pozwala na kontynuowanie pozostałej części przepływu.źródło
Exception
s jak najbardziej, ale nieThrowable
.