Martwię się, że jest to wyjątek w czasie wykonywania, więc prawdopodobnie powinno być używane oszczędnie.
Standardowy przypadek użycia:
void setPercentage(int pct) {
if( pct < 0 || pct > 100) {
throw new IllegalArgumentException("bad percent");
}
}
Ale wydaje się, że wymusiłoby to następujący projekt:
public void computeScore() throws MyPackageException {
try {
setPercentage(userInputPercent);
}
catch(IllegalArgumentException exc){
throw new MyPackageException(exc);
}
}
Aby przywrócić go jako sprawdzony wyjątek.
Dobra, ale chodźmy z tym. Jeśli podasz złe dane wejściowe, pojawi się błąd wykonania. Po pierwsze, jest to dość trudna zasada do jednolitego wdrożenia, ponieważ może być konieczne wykonanie odwrotnej konwersji:
public void scanEmail(String emailStr, InputStream mime) {
try {
EmailAddress parsedAddress = EmailUtil.parse(emailStr);
}
catch(ParseException exc){
throw new IllegalArgumentException("bad email", exc);
}
}
Co gorsza - o ile 0 <= pct && pct <= 100
można oczekiwać statycznego sprawdzenia kodu klienta, nie dotyczy to bardziej zaawansowanych danych, takich jak adres e-mail, lub, co gorsza, czegoś, co należy sprawdzić w bazie danych, dlatego generalnie kod klienta nie może wstępnie uprawomocnić.
Zasadniczo mówię, że nie widzę sensownej, spójnej polityki dotyczącej używania IllegalArgumentException
. Wydaje się, że nie należy go używać i powinniśmy trzymać się własnych sprawdzonych wyjątków. Jaki jest dobry przypadek użycia, aby to wyrzucić?
źródło
Mówiąc o „złym wejściu”, należy zastanowić się, skąd pochodzi dane wejściowe.
Jeśli dane wejściowe zostały wprowadzone przez użytkownika lub inny system zewnętrzny, nad którym nie masz kontroli, należy oczekiwać, że dane wejściowe będą nieprawidłowe i zawsze je sprawdzać. W tym przypadku można zgłosić wyjątek zaznaczony. Twoja aplikacja powinna „odzyskać” po tym wyjątku, przekazując użytkownikowi komunikat o błędzie.
Jeśli dane wejściowe pochodzą z twojego własnego systemu, np. Bazy danych lub innych części twojej aplikacji, powinieneś być w stanie polegać na tym, że jest poprawny (powinien zostać zweryfikowany zanim tam dotarł). W tym przypadku jest całkowicie w porządku, aby zgłosić niezaznaczony wyjątek, taki jak IllegalArgumentException, którego nie należy przechwytywać (generalnie nigdy nie należy łapać niezaznaczonych wyjątków). To błąd programisty, że w pierwszej kolejności trafiła tam nieprawidłowa wartość;) Musisz to naprawić.
źródło
Because an unchecked exception is meant to be thrown as a result of a programming error
pomogło mi wyczyścić wiele rzeczy z mojej głowy, dziękuję :)Rzucanie wyjątków w czasie wykonywania „oszczędnie” nie jest naprawdę dobrą polityką - efektywna Java zaleca używanie sprawdzonych wyjątków, gdy można racjonalnie oczekiwać, że wywołujący odzyska . (Błąd programisty jest konkretnym przykładem: jeśli konkretny przypadek wskazuje na błąd programisty, powinieneś zgłosić niesprawdzony wyjątek; chcesz, aby programista miał ślad stosu, gdzie wystąpił problem logiczny, a nie próbować samodzielnie go obsłużyć).
Jeśli nie ma nadziei na wyzdrowienie, możesz skorzystać z niezaznaczonych wyjątków; nie ma sensu ich łapać, więc to jest w porządku.
Z twojego przykładu nie wynika jednak w 100%, który przypadek znajduje się w twoim kodzie.
źródło
foo(data)
Mogłaby wystąpić dowolna operacja , w ramachfor(Data data : list) foo(data);
której wywołujący mógłby chcieć, aby jak najwięcej zakończyło się sukcesem, nawet jeśli niektóre dane są źle sformułowane. Obejmuje również błędy programistyczne, jeśli awaria mojej aplikacji oznacza, że transakcja nie przejdzie, to prawdopodobnie lepiej, jeśli oznacza to, że chłodzenie jądrowe przechodzi w tryb offline, to źle.StackOverflowError
i są to przypadki, po których nie można racjonalnie oczekiwać, że dzwoniący wyzdrowieje. Ale wygląda na to, że należy sprawdzić każdą wielkość liter na poziomie logiki danych lub aplikacji. Oznacza to, że sprawdzaj swój pusty wskaźnik!Jak określono w oficjalnym samouczku Oracle, stwierdza się, że:
Jeśli mam aplikację korzystającą z bazy danych przy użyciu
JDBC
i mam metodę, która przyjmuje argument jakoint item
idouble price
.price
Do odpowiedniego elementu jest odczytywany z tabeli bazy danych. Po prostu mnożę całkowitą liczbęitem
zakupów przezprice
wartość i zwracam wynik. Chociaż zawsze jestem pewien na końcu (koniec aplikacji), że wartość pola ceny w tabeli nigdy nie może być ujemna, ale co, jeśli wartość ceny wyjdzie ujemna ? Pokazuje, że po stronie bazy danych jest poważny problem. Być może błędne wprowadzenie ceny przez operatora. Jest to rodzaj problemu, którego druga część aplikacji wywołująca tę metodę nie może przewidzieć i nie może jej naprawić. To jestBUG
w twojej bazie danych. Tak iIllegalArguementException()
należy wyrzucić w tym przypadku, co by to oznaczałothe price can't be negative
.Mam nadzieję, że jasno wyraziłem swój punkt widzenia.
źródło
Każde API powinno sprawdzić poprawność każdego parametru dowolnej metody publicznej przed jej wykonaniem:
Stanowią 99,9% przypadków błędów w aplikacji, ponieważ prosi ona o niemożliwe operacje, więc ostatecznie są to błędy, które powinny spowodować awarię aplikacji (więc jest to błąd nieodwracalny).
W takim przypadku i zgodnie z podejściem polegającym na szybkim niepowodzeniu, należy pozwolić aplikacji zakończyć się, aby uniknąć uszkodzenia stanu aplikacji.
źródło
Potraktuj
IllegalArgumentException
jako sprawdzenie warunków wstępnych i rozważ zasadę projektowania: metoda publiczna powinna zarówno znać, jak i publicznie dokumentować swoje własne warunki wstępne.Zgadzam się, że ten przykład jest poprawny:
Jeśli EmailUtil jest nieprzezroczysty , co oznacza, że z jakiegoś powodu warunki wstępne nie mogą być opisane użytkownikowi końcowemu, to zaznaczony wyjątek jest poprawny. Druga wersja, poprawiona dla tego projektu:
Jeśli EmailUtil jest przezroczysty , na przykład może jest to prywatna metoda należąca do danej klasy,
IllegalArgumentException
jest poprawna wtedy i tylko wtedy, gdy jej warunki wstępne można opisać w dokumentacji funkcji. To jest również poprawna wersja:Ten projekt może iść w obie strony.
ParseException
. Nazwa metody najwyższego poziomuscanEmail
wskazuje, że użytkownik końcowy zamierza wysłać niezbadaną wiadomość e-mail, więc prawdopodobnie jest to poprawne.IllegalArgumentException
. Chociaż nie jest „zaznaczone”, „czek” przenosi się do Javadoc dokumentującego funkcję, do której klient powinien się stosować.IllegalArgumentException
gdy klient nie może wcześniej stwierdzić, że jego argument jest nielegalny, jest błędny.Uwaga dotycząca wyjątku IllegalStateException : Oznacza to, że „stan wewnętrzny tego obiektu (zmienne instancji prywatnej) nie może wykonać tej czynności”. Użytkownik końcowy nie widzi stanu prywatnego tak luźno mówiąc, że ma on pierwszeństwo
IllegalArgumentException
w przypadku, gdy wywołanie klienta nie ma możliwości sprawdzenia, czy stan obiektu jest niespójny. Nie mam dobrego wyjaśnienia, kiedy jest to preferowane od sprawdzonych wyjątków, chociaż przykładami są takie rzeczy, jak dwukrotna inicjalizacja lub utrata połączenia z bazą danych, które nie jest odzyskiwane.źródło