2009-10-16 10 views
6

Mam spotkanie standardów kodowania w nieco ponad godzinę i potrzebuję szybkiej odpowiedzi na to.Potrzebujesz wiarygodnego źródła, dla którego nie powinieneś rzucać lub łapać java.lang.Exception

Powszechną wiedzą wśród doświadczonych programistów Java jest to, że nie rzuca się ani nie przechwytuje wyjątku java.lang.Exception (z rzadkimi wyjątkami - gra słów nie jest przeznaczona). Powodem nie rób tego jest to, że oświadczenie

catch (java.lang.Exception ex) {...} 

również złapać niezaznaczone wyjątkami, w większości przypadków nie jest to, co jest przeznaczone.

Mamy już wiele starszych kodów napisanych przez istniejących członków zespołu, którzy przechwytują podklasę klasy java.lang.Exception, rejestrują błąd i ponownie rzucają podklas jako wyjątek java.lang.Exception.

muszę przekonać ich, że

  1. Muszą przestać pisać kod w ten sposób.
  2. Istniejący kod, który używa tego anty-wzorzec musi być ustalona

Numer 2 oznacza sporo refaktoringu.

Spowoduje to skrócenie argumentacji na spotkaniu, jeśli mogę wyświetlić artykuł lub wpis na blogu jednego z członków społeczności Java wagi ciężkiej, który to czyni (np. Joshua Bloch, James Gosling). Mój google-fu jeszcze niczego nie odkrył.

Czy ktoś wie o artykule lub blogu szanowanego guru Java, który mówi, że nie powinieneś rzucać lub łapać java.lang.Exception?

Szybkie odpowiedzi są mile widziane.

Dean

+1

prostu chcą pokazać, że pytanie: http://stackoverflow.com/questions/237585/java-lang-exception-vs-rolling-your-own-exception kilka przyjemnych odpowiedzi w nim – bastianneu

+0

I przeczytaj to przed opublikowaniem tego. Kilka odpowiedzi i komentarzy mówi to samo, ale szukam autorytetu. Doprowadzi to do znacznej ilości refaktoryzacji, aby pomóc w uzyskaniu opinii eksperta, która poparłaby mnie. –

Odpowiedz

0

Chyba chodzi o to, że jeśli nie wiesz jak obsługiwać konkretny wyjątek to nie powinien go złapać. Powinien rozprzestrzeniać się na wyższy poziom w nadziei, że będzie wiedział, co z tym zrobić. Łapanie wyjątków zbyt wcześnie prowadzi do po cichu połkniętych wyjątków i uniemożliwia im zrobienie z nich czegoś pożytecznego poza logowaniem.

Wyobraź sobie, co by się stało, gdyby konstruktor FileInputStream miał wewnętrznie zarejestrować wyjątek, jeśli próbowałeś otworzyć plik, który nie istnieje, ale nie wskazałeś tego błędu w kodzie. Nie ma problemu, że błąd zostanie zarejestrowany, ale twój kod chciałby przechwycić ten wyjątek i zrobić z nim coś użytecznego (np. Monitując użytkownika o nową nazwę pliku). Gdyby mieli catch (Exception), nie bylibyście w stanie tego zrobić.

0

Jeśli masz pod ręką efektywną Javę Josh Blocha, wiem, że omawia tutaj obsługę wyjątków. Obecnie nie mam do niego dostępu, więc nie mogę podsumować go ani podać referencji do strony, ale jestem prawie pewny, że ma kilka dobrych argumentów za nieotrzymaniem java.lang.Exception.

+1

To byłby rozdział 9 (17 stron). On nie preferuje żadnej z nich, ale podkreśla fakt, że powinieneś używać tylko sprawdzonych wyjątków, jeśli osoba dzwoniąca może coś zrobić z tym problemem. Tak więc OOM jest RuntimeExc., Podczas gdy NoMoreElements jest (złym) sprawdzonym excem. –

3

Nie ma tutaj wspólnej płaszczyzny.Znajdziesz tu dwie grupy:

  1. Ci, którzy nienawidzą sprawdzane wyjątki złapie i owinąć je w RuntimeException pewnego rodzaju.

  2. Ci, którzy nienawidzą RuntimeException

Pierwsza grupa nienawidzi zagadkę ich kodu z try...catch, zwłaszcza, że ​​w większości przypadków nie można obsłużyć wyjątek, kiedy pierwszy raz to widzę. Pomyśl IOException: Można go rzucić na każdy bajt, który czytasz. Jaki jest kod niskiego poziomu, który można z tym zrobić? Musi go ponownie rzucić, aby ktoś wyższy mógł dodać użyteczny kontekst do błędu (np. Który plik czytałeś).

Druga grupa chce zobaczyć, co może pójść nie tak. RuntimeException skutecznie to ukrywa.

Istnieje prosta poprawka, BTW: Make Exception rozszerzający wyjątek RuntimException. Szalony? Nie całkiem. Jeśli zrobisz to za pomocą JDK 7, otrzymasz dwa błędy kompilacji.

Następnym krokiem będzie sprawdzenie, czy wszystkie kompilatory Java wyliczają wszystkie wyjątki środowiska wykonawczego i wyświetlają je w pozycji throws w pliku klasy. Nadal nie musisz ich łapać, ale teraz wiesz, które z nich mogą się wydarzyć.

Na koniec, rozszerz IDE, aby to wyświetlić. I presto, obie grupy mogłyby być szczęśliwe. Niestety tak się nie stanie.

+0

Trochę chaotyczna, ale lubię to! –

+0

Osoby, które lubią sprawdzane wyjątki, nie nienawidzą wyjątków w czasie wykonywania, ograniczają tylko ich użycie do sytuacji, w których są odpowiednie. – Brian

+0

@Brian: Moim argumentem jest to, że nie ma sposobu, aby uzgodnić, kiedy są one "odpowiednie". "Wyjątek SQLEx" i "IOException" to w mojej opinii wyjątki środowiska wykonawczego, ponieważ z mojego doświadczenia wynika, że ​​są one rzucane częściej z powodu błędu programowania, a nie ze względu na warunek, który mógł obsłużyć wywołujący. –

5

Zobacz this article z Brian Goetz (kreator współbieżności), który ma swoją własną wiedzę, a także podając Josh Bloch w Effective Java

2

gdzie złapią podklasę java.lang.Exception zalogować błąd, i ponownie podklasę podklasy jako wyjątek java.lang.Exception. Muszę ich przekonać, że muszą przestać pisać taki kod.

Zgadzam się, że należy zastosować inną taktykę, ale z różnych powodów. Nie ma większego sensu chwytanie wyjątku tylko po to, aby go zarejestrować i ponownie rzucić.

Alternatywą jest: nie przechwytuj wyjątku i pozwól, aby wyższy kod (jak filtr Java EE lub try/catch w metodzie main()) przechwytywał i rejestrował wszystkie nieprzechwycone wyjątki. Wtedy upewnisz się, że każdy wyjątek jest rejestrowany tylko raz i wiesz, że wszystkie nieprzechwycone wyjątki będą rejestrowane.

Aby dodać dodatkowe informacje do wyjątku, należy go przechwycić, zmienić wiadomość i ponownie ją przesłać.Zwykle używam RuntimeException na to:

} catch (Exception originalException) { 
    throw new RuntimeException("user name was " + userName, originalException); 
} 
+0

Wyjątki powinny być rejestrowane tak blisko miejsca, w którym zostały zgłoszone. Możliwe, że gdzieś w głąb Wyjątku zostanie połknięty lub wystąpi inny błąd lub wyjątek RuntimeException (np. NullPointerException), który uniemożliwi rejestrowanie w dalszym ciągu. Czy chodziło Ci o powyższe wyrażenie catch(), aby uchwycić wyjątek RuntimeException? –

+0

@Dean Schulze prawdopodobnie, jeśli wyjątek został połknięty, oznacza to, że nie był to nieoczekiwany wyjątek, ale był oczekiwany i kod wiedział, jak go programowo obsłużyć. Inny sposób na stwierdzenie tego: ktokolwiek obsługuje wyjątek, powinien go zarejestrować. Jeśli jest nieobsługiwany do końca, powinieneś mieć mechanizm do obsługi i rejestrowania tych nieoczekiwanych wyjątków. Dzięki temu ślad stosu pojawia się tylko raz w dziennikach. –

+0

@Dean Schulze zgodnie z instrukcją catch catch Exception, tak, próbowałem pokazać, że nie musisz rejestrować błędów i wartości zmiennych dziennika, gdy wyjątek zostanie przechwycony. Zamiast tego można uchwycić wyjątek i dodać te wartości do wiadomości, a następnie zawinąć wyjątek i ponownie go rzucić. Twoje dodatkowe dane nadal są zapisywane w dziennikach (a ślad stosu jest wysyłany tylko raz, co ułatwia wyszukiwanie dzienników w poszukiwaniu błędów). –

1

to jest długi artykuł ale this proponuje Ci:

  1. użycie sprawdzane wyjątki, gdy klient oczekuje tego błędu regularnie występować i musi je (ex obsłużyć: Użytkownik dane -entered nie przechodzą walidację)
  2. użytku niesprawdzony wyjątki dla niespodziewanych warunkach (np: serwer DB zszedł)

W teorii, # 1 (exp omówione błędy) powinny mieć swój własny typ wyjątku, a jedynym miejscem, które powinno wychwycić # 2 (wyjątek RuntimeException) jest pewien rodzaj obsługi najwyższego poziomu, który przechwytuje wyjątek, rejestruje go i pokazuje użytkownikowi komunikat o błędzie, a nawet tutaj prawdopodobnie powinieneś złapać Throwable, aby upewnić się, że obsługiwane są wszystkie nieprzechwycone wyjątki.

Postępując zgodnie z tymi wskazówkami, nie należy przechwytywać wyjątków, ponieważ nie spełniają one żadnego z powyższych kryteriów (co oznacza, że ​​nie jest to wyjątek RuntimeException i nie jest to wyspecjalizowana podszewka wyjątku wskazująca oczekiwany błąd).

+1

Adres URL artykułu, do którego się odwołano [zmienił się] (http://www.oracle.com/technetwork/articles/entarch/effective-exceptions-092345.html). @TerrelShumway opublikował ten sam artykuł w swojej odpowiedzi. Naprawiono poprawkę – hotshot309

+0

@ hotshot309. Dziękuję Ci! –

+0

Osoby, które lubią sprawdzane wyjątki, nie nienawidzą wyjątków w czasie wykonywania, ograniczają tylko ich użycie do sytuacji, w których są odpowiednie. – Brian

1

Tutaj jest bardzo insightful article

Podsumowanie:

  1. Korzystanie sprawdzone wyjątki dla nielicznych, ale ważnych warunkowych, które odnoszą się do celów kodzie. Kod klienta powinien wiedzieć, jak sobie z nimi radzić.

  2. Użyj niezaznaczonych wyjątków dla błędów, które nie powinny się zdarzyć, ale wykonaj. (Nie działa serwer, błędnie skonfigurowana ścieżka klasy, błąd składni SQL itd.) Facet od zarządzania serwerem IT lub programista, który właśnie przekazał zły SQL do funkcji prepareStatement() powinien wiedzieć, jak rozwiązać te problemy. Błędy powinny rozprzestrzeniać się do warstwy rejestrowania, aby informacje nie zostały utracone.

Powiązane problemy