2013-03-04 9 views
67

Obawiam się, że jest to wyjątek środowiska wykonawczego, więc prawdopodobnie powinien być używany oszczędnie.
Standardowy przypadek użycia:Kiedy należy rzucić wyjątek IllegalArgumentException?

void setPercentage(int pct) { 
    if(pct < 0 || pct > 100) { 
     throw new IllegalArgumentException("bad percent"); 
    } 
} 

Ale wydaje się, że byłoby wymusić następującą konstrukcję:

public void computeScore() throws MyPackageException { 
     try { 
      setPercentage(userInputPercent); 
     } 
     catch(IllegalArgumentException exc){ 
      throw new MyPackageException(exc); 
     } 
} 

Aby dostać go z powrotem do bycia sprawdzone wyjątkiem.

OK, ale chodźmy z tym. Jeśli wprowadzisz złe dane wejściowe, pojawi się błąd runtime. Więc po pierwsze, że to rzeczywiście dość trudne polityka wdrożyć jednolity, ponieważ może trzeba zrobić bardzo przeciwny konwersję:

public void scanEmail(String emailStr, InputStream mime) { 
    try { 
     EmailAddress parsedAddress = EmailUtil.parse(emailStr); 
    } 
    catch(ParseException exc){ 
     throw new IllegalArgumentException("bad email", exc); 
    } 
} 

a co gorsza - podczas sprawdzania 0 <= pct && pct <= 100 kodu klient powinien był zrobić statycznie, to nie jest tak w przypadku bardziej zaawansowanych danych, takich jak adres e-mail lub, co gorsza, coś, co należy sprawdzić w bazie danych, dlatego ogólnie kod klienta nie może wstępnie zatwierdzić.

W gruncie rzeczy mówię, że nie widzę sensownej, spójnej polityki w zakresie korzystania z IllegalArgumentException. Wygląda na to, że nie powinno się go używać i powinniśmy trzymać się naszych sprawdzonych wyjątków. Co to jest dobry przypadek, aby to rzucić?

Odpowiedz

51

Doc api dla IllegalArgumentException jest:

rzucony wskazują, że metoda została przekazana nielegalne lub nieodpowiednie argument.

Od patrząc na how it is used in the jdk libraries, powiedziałbym:

  • Wydaje się, że środek ochronny narzekać oczywiście złe wejście przed wejście może dostać się do prac i powodować coś nie w połowie drogi za pomocą bezsensownego komunikatu o błędzie.

  • Służy do przypadków, w których byłoby to zbyt uciążliwe, aby rzucić sprawdzonej wyjątek (choć to sprawia, że ​​wygląd w kodzie java.lang.reflect, gdzie troska o absurdalnych poziomów sprawdzonej wyjątku rzucanie nie jest inaczej widoczne).

użyłbym IllegalArgumentException zrobić w ostatniej rów obronny argumentem sprawdzania wspólnych narzędzi (starając się pozostać spójne z wykorzystaniem JDK), gdzie oczekuje się, że to zły argument jest błąd programista, podobny do NPE. Nie użyłbym go do wdrożenia walidacji w kodzie biznesowym. Na pewno nie użyłbym go do przykładu e-mailowego.

+5

Myślę, że rada "gdzie oczekiwano, że zły argument jest błędem programisty" jest najbardziej spójna z tym, jak widziałem to używane, więc akceptując tę ​​odpowiedź. – djechlin

9

Throwing wyjątki środowiska wykonawczego „oszczędnie” nie jest naprawdę dobra polityka - Skuteczne Java zaleca stosowanie sprawdzonych wyjątków kiedy można zasadnie oczekiwać rozmówca odzyskać. (Błąd programisty jest konkretnym przykładem: jeśli konkretny przypadek wskazuje na błąd programisty, powinieneś rzucić niezaznaczony wyjątek, chcesz, aby programista miał ślad stosu miejsca, w którym wystąpił problem logiczny, a nie próbował go obsłużyć samodzielnie.)

Jeśli nie ma nadziei na odzyskanie, możesz użyć niezaznaczonych wyjątków; nie ma sensu ich łapać, więc to jest w porządku.

Na przykładzie nie jest w 100% jasne, który przypadek znajduje się w Twoim kodzie.

+0

Myślę, że "rozsądnie oczekuje się, że wyzdrowieją" to łasica. Dowolna operacja 'foo (dane)' mogła wystąpić jako część 'for (Data data: list) foo (data);' w której wywołujący mógłby chcieć jak najwięcej, aby odnieść sukces, nawet jeśli niektóre dane są zniekształcone.Obejmuje również błędy programistyczne, jeśli moja aplikacja zawiedzie oznacza, że ​​transakcja nie przejdzie przez to, prawdopodobnie jest lepsza, jeśli oznacza to, że chłodzenie nuklearne przechodzi w tryb offline, który jest zły. – djechlin

+0

'StackOverflowError' i takie są przypadki, od których nie można w uzasadniony sposób oczekiwać odzyskania połączenia. Wygląda jednak na to, że należy sprawdzić przypadek poziomu logiki danych lub aplikacji. Oznacza to, że twój zerowy wskaźnik sprawdza! – djechlin

+3

W aplikacji do chłodzenia nuklearnego wolałbym ciężko przejść testy, niż pozwolić na to, aby programista uważał, że niemożliwe jest przejść niezauważenie. –

4

Jak podano w oficjalnym poradniku oracle, stwierdza, że:

Jeśli można zasadnie oczekiwać klient, aby odzyskać od wyjątek, sprawiają, że zaznaczone jest wyjątkiem. Jeśli klient nie może nic zrobić, aby odzyskać z wyjątku, ustaw niezaznaczony wyjątek.

Jeśli Mam aplikacji interakcji z bazą danych przy użyciu JDBC i mam metodę, która przyjmuje argument jako int item i double price. price dla odpowiedniego elementu jest odczytywany z tabeli bazy danych. Po prostu pomnożę łączną liczbę item zakupioną z wartością price i zwróć wynik. Mimo, że 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 negatywny? Pokazuje to, że strona bazy danych ma poważny problem. Być może błędne wprowadzenie ceny przez operatora. Jest to kwestia, której druga część aplikacji wywołująca tę metodę nie jest w stanie przewidzieć i nie może jej odzyskać. Jest to BUG w bazie danych.Tak więc i IllegalArguementException() powinien być wyrzucony w tym przypadku, który stwierdziłby, że the price can't be negative.
Mam nadzieję, że mój punkt wyraziły jasno ..

17

Mówiąc o "złych danych wejściowych", należy wziąć pod uwagę, skąd pochodzą dane wejściowe.

Czy dane wprowadzane przez użytkownika lub inny system zewnętrzny, który nie jest kontrolowany, należy oczekiwać, że dane wejściowe będą nieprawidłowe i zawsze je sprawdzać. W tym przypadku można całkowicie rzucić sprawdzony wyjątek. Twoja aplikacja powinna "odzyskać" ten wyjątek, przekazując użytkownikowi komunikat o błędzie.

Jeśli dane wejściowe pochodzą z własnego systemu, np. Twoja baza danych lub niektóre inne części aplikacji, powinieneś być w stanie na niej polegać (powinna była zostać zatwierdzona, zanim dotarła na miejsce). W tym przypadku jest całkowicie w porządku, aby rzucić niesprawdzony wyjątek, taki jak IllegalArgumentException, który nie powinien zostać przechwycony (generalnie nie powinieneś przechwytywać niesprawdzonych wyjątków). Jest to błąd programisty, że w pierwszej kolejności pojawiła się nieprawidłowa wartość;) Musisz to naprawić.

+1

Dlaczego "nigdy nie powinno się łapać niezaznaczonych wyjątków"? –

+5

Ponieważ niesprawdzony wyjątek ma być wywołany w wyniku błędu programowania. Od osoby wywołującej metodę, która rzuca takie wyjątki, nie można oczekiwać, że do niej dojdzie, i dlatego zazwyczaj nie ma sensu ich łapać. – Tom

+0

'Ponieważ niezaznaczony wyjątek ma być wyrzucony w wyniku błędu w programowaniu' pomógł mi wyczyścić wiele rzeczy w mojej głowie, dziękuję :) – svarog

5

Wszelkie API powinien sprawdzić ważność każdego parametru jakiejkolwiek metody publicznej przed wykonaniem go:

void setPercentage(int pct, AnObject object) { 
    if(pct < 0 || pct > 100) { 
     throw new IllegalArgumentException("pct has an invalid value"); 
    } 
    if (object == null) { 
     throw new IllegalArgumentException("object is null"); 
    } 
} 

Stanowią one 99,9% czasu błędów we wniosku, ponieważ jest on z prośbą o operacjach niemożliwych więc w na końcu są to błędy, które powinny spowodować awarię aplikacji (więc jest to błąd niemożliwy do naprawienia).

W tym przypadku i zgodnie z podejściem fail fail należy zakończyć aplikację, aby uniknąć uszkodzenia stanu aplikacji.

+0

Wręcz przeciwnie, jeśli klient API daje mi złe dane wejściowe, powinien * nie * zawieść mojego całego serwera API. – djechlin

+0

Oczywiście nie powinien on zawieść twojego serwera API, ale zwrócić wyjątek do wywołującego, który nie powinien powodować awarii z wyjątkiem klienta. –

+0

To, co napisałeś w komentarzu, nie jest tym, co napisałeś w odpowiedzi. – djechlin

Powiązane problemy