Rozważmy sytuację, w której masz podany kod:
public void delete() throws IOException, SQLException { // Non-Compliant
/* ... */
}
Niebezpieczeństwo polega na tym, że kod, który piszesz, aby zadzwonić, delete()
będzie wyglądał następująco:
try {
foo.delete()
} catch (Exception e) {
/* ... */
}
To też jest złe. I zostanie złapany z inną regułą, że flagi przechwytują podstawową klasę wyjątków.
Kluczem jest nie pisać kodu, który powoduje, że chcesz pisać zły kod w innym miejscu.
Zasada, którą napotykasz, jest dość powszechna. Checkstyle ma to w swoich regułach projektowych:
ThrowsCount
Ogranicza wyrzuca instrukcje do określonej liczby (domyślnie 1).
Uzasadnienie: wyjątki stanowią część interfejsu metody. Zadeklarowanie metody generowania zbyt wielu różnie zakorzenionych wyjątków powoduje, że obsługa wyjątków jest uciążliwa i prowadzi do złych praktyk programistycznych, takich jak pisanie kodu, np. Catch (Exception ex). Ta kontrola zmusza programistów do umieszczenia wyjątków w hierarchii, tak aby w najprostszym przypadku wywołujący mógł sprawdzić tylko jeden typ wyjątku, ale w razie potrzeby można było przechwycić wszelkie podklasy.
To precyzyjnie opisuje problem i na czym polega problem i dlaczego nie powinieneś tego robić. Jest to dobrze przyjęty standard, który identyfikuje i oflaguje wiele narzędzi do analizy statycznej.
I chociaż możesz to zrobić zgodnie z projektem języka, a czasem mogą to być właściwe działania, jest to coś, co powinieneś zobaczyć i od razu powiedzieć „hmm, dlaczego to robię?” Może to być akceptowalne w przypadku kodu wewnętrznego, w którym każdy jest wystarczająco zdyscyplinowany, aby nigdy catch (Exception e) {}
, ale częściej widziałem, jak ludzie skracają rogi, szczególnie w sytuacjach wewnętrznych.
Nie zmuszaj osób korzystających z twojej klasy do pisania złego kodu.
Powinienem zauważyć, że znaczenie tego jest mniejsze w Javie SE 7 i nowszych, ponieważ pojedyncza instrukcja catch może wychwycić wiele wyjątków (przechwytywanie wielu typów wyjątków i ponowne sprawdzanie wyjątków dzięki ulepszonemu sprawdzaniu typów z Oracle).
W Javie 6 i wcześniejszych kod wyglądałby następująco:
public void delete() throws IOException, SQLException {
/* ... */
}
i
try {
foo.delete()
} catch (IOException ex) {
logger.log(ex);
throw ex;
} catch (SQLException ex) {
logger.log(ex);
throw ex;
}
lub
try {
foo.delete()
} catch (Exception ex) {
logger.log(ex);
throw ex;
}
Żadna z tych opcji w Javie 6 nie jest idealna. Pierwsze podejście narusza SUSZENIE . Wiele bloków robi to samo, raz po raz - raz dla każdego wyjątku. Chcesz zarejestrować wyjątek i ponownie go wrzucić? Dobrze. Te same wiersze kodu dla każdego wyjątku.
Druga opcja jest gorsza z kilku powodów. Po pierwsze, oznacza to, że wychwytujesz wszystkie wyjątki. Wskaźnik zerowy zostaje tam złapany (i nie powinien). Ponadto, jesteś Ponowne generowanie e Exception
co oznacza, że podpis metodą byłoby deleteSomething() throws Exception
który właśnie robi bałagan dalej na stosie jako osób korzystających z kodu są teraz zmuszeni do catch(Exception e)
.
W Javie 7 nie jest to tak ważne, ponieważ zamiast tego możesz:
catch (IOException|SQLException ex) {
logger.log(ex);
throw ex;
}
Ponadto rodzaj sprawdzenia, czy jeden ma złapać rodzaje wyjątków wyrzucane:
public void rethrowException(String exceptionName)
throws IOException, SQLException {
try {
foo.delete();
} catch (Exception e) {
throw e;
}
}
Kontroler typów rozpozna, że e
mogą być tylko typy IOException
lub SQLException
. Nadal nie jestem zbyt entuzjastycznie nastawiony do korzystania z tego stylu, ale nie powoduje on tak złego kodu, jak był w Javie 6 (gdzie zmusiłoby cię to, aby podpis metody był nadklasą, którą rozszerzają wyjątki).
Pomimo tych wszystkich zmian, wiele narzędzi analizy statycznej (Sonar, PMD, Checkstyle) wciąż wymusza przewodniki po stylu Java 6. To nie jest złe. I mają tendencję do uzgodnienia z ostrzeżeniem do nich nadal być egzekwowane, ale można zmienić priorytet na nich do większych lub mniejszych w zależności od sposobu ich zespół priorytet.
Jeśli wyjątki powinny być zaznaczone lub odznaczone ... że jest to kwestia g r e a t debaty , które mogą łatwo znaleźć niezliczonych blogach biorących się z każdej strony argumentu. Jeśli jednak pracujesz z zaznaczonymi wyjątkami, prawdopodobnie powinieneś unikać rzucania wielu typów, przynajmniej w Javie 6.