Kiedy należy wyrzucić niezgodny z Prawem dokument?

Obawiam się, że jest to wyjątek runtime, więc prawdopodobnie powinien być używany 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ącą konstrukcję:

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

Aby przywrócić wyjątek sprawdzony.

/ Align = "left" / Jeśli podasz złe dane wejściowe, pojawi się błąd runtime. Więc po pierwsze, jest to dość trudna Polityka do wdrożenia w sposób jednolity, ponieważ można zrobić coś zupełnie odwrotnego konwersja:
public void scanEmail(String emailStr, InputStream mime) {
    try {
        EmailAddress parsedAddress = EmailUtil.parse(emailStr);
    }
    catch(ParseException exc){
        throw new IllegalArgumentException("bad email", exc);
    }
}

I co gorsza-podczas sprawdzania 0 <= pct && pct <= 100 kodu klienta można oczekiwać statycznie, nie jest tak w przypadku bardziej zaawansowanych danych, takich jak adres e-mail, lub co gorsza, czegoś, co musi być sprawdzone w bazie danych, dlatego ogólnie kod klienta nie może wstępnie zweryfikować.

Więc zasadniczo chodzi mi o to, że nie widzę sensownej spójnej polityki użycia IllegalArgumentException. Wydaje się, że nie powinien być używany i powinniśmy trzymać się własnych sprawdzonych WYJĄTKÓW. Co to jest dobry przykład, żeby to rzucić?

Author: APerson, 2013-03-04

6 answers

Dokument api dla IllegalArgumentException to:

Rzucony, aby wskazać, że metoda została przekazana niezgodny z prawem lub niewłaściwy argument.

Patrząc na Jak jest używany w bibliotekach jdk , powiedziałbym:

  • Wydaje się, że defensywnym środkiem jest narzekanie na oczywiście złe dane wejściowe, zanim dane wejściowe wejdą do pracy i spowodują, że coś zawiedzie w połowie z nonsensownym błędem wiadomość.

  • Jest używany w przypadkach, w których rzucanie wyjątku checked byłoby zbyt irytujące (chociaż pojawia się w Javie.lang.reflect code, gdzie obawa o absurdalne poziomy checked-exception-throwing nie jest inaczej widoczna).

Użyłbym IllegalArgumentException do sprawdzania defensywnego argumentu last-ditch dla wspólnych narzędzi( starając się pozostać spójnym z użyciem jdk), gdzie oczekiwaniem jest, że zły argument jest błąd programisty, podobny do NPE. Nie używałbym go do implementacji walidacji w kodzie biznesowym. Na pewno nie użyłbym go do przykładu e-maila.

 57
Author: Nathan Hughes,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2013-03-04 19:56:54

Mówiąc o "złych wejściach", powinieneś rozważyć, skąd pochodzą dane wejściowe.

To dane wejściowe wprowadzone przez użytkownika lub inny zewnętrzny system, nad którym nie kontrolujesz, powinieneś oczekiwać, że dane wejściowe będą nieprawidłowe i zawsze je walidować. W tym przypadku w porządku jest rzucanie zaznaczonego wyjątku. Twoja aplikacja powinna "odzyskać" z tego wyjątku, dostarczając użytkownikowi komunikat o błędzie.

Jeśli dane wejściowe pochodzą z twojego własnego systemu, np. Twojej bazy danych lub innego części twojej aplikacji, powinieneś być w stanie polegać na tym, że jest ważna (powinna być zatwierdzona, zanim się tam dostała). W tym przypadku jest całkowicie w porządku rzucać niezaznaczony wyjątek, taki jak IllegalArgumentException, który nie powinien być przechwytywany(ogólnie rzecz biorąc, nigdy nie należy przechwytywać niezaznaczonych WYJĄTKÓW). To błąd programisty, że nieprawidłowa wartość dotarła tam w pierwszej kolejności ;) trzeba to naprawić.

 19
Author: Tom,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2017-10-07 18:52:46

Rzucanie WYJĄTKÓW środowiska wykonawczego "oszczędnie" nie jest zbyt dobrą polityką -- skuteczna Java zaleca używanie WYJĄTKÓW sprawdzonych, gdy można oczekiwać, że wywołujący odzyska . (Błąd programisty jest konkretnym przykładem: jeśli konkretny przypadek wskazuje 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ć samodzielnie go obsłużyć.)

Jeśli nie ma nadziei na wyzdrowienie, nie ma sensu ich łapać, więc jest to całkowicie w porządku.

To nie jest w 100% Jasne z twojego przykładu, w którym przypadku ten przykład jest w Twoim kodzie.

 10
Author: Louis Wasserman,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2013-03-04 18:40:07

Każde API powinno sprawdzić poprawność każdego parametru dowolnej publicznej metody przed jej wykonaniem:

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");
    }
}

Reprezentują 99,9% błędów w aplikacji, ponieważ prosi o niemożliwe operacje, więc w końcu są to błędy, które powinny zawiesić aplikację(więc jest to błąd nie do odzyskania).

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

 5
Author: Ignacio Soler Garcia,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2015-12-17 11:47:12

[[9]} jak określono w oficjalnym samouczku oracle, stwierdza się, że:

Jeśli można racjonalnie oczekiwać, że klient wyzdrowieje z wyjątku, niech to będzie zaznaczony wyjątek. Jeśli klient nie może nic zrobić, aby odzyskać od wyjątku należy uczynić go wyjątkiem niezaznaczonym.

Jeśli mam aplikację oddziałującą z bazą danych za pomocą JDBC, i mam metodę, która przyjmuje argument jako int item i double price. price dla odpowiedniego elementu odczytuje się z tabela bazy danych. Wystarczy pomnożyć całkowitą liczbę item zakupionych przez wartość price i zwrócić wynik. Chociaż zawsze jestem pewien na moim końcu (koniec aplikacji), że wartość pola price w tabeli nigdy nie może być ujemna .Ale co jeśli wartość ceny wyjdzie ujemna ? Pokazuje to, że istnieje poważny problem ze stroną bazy danych. Być może błędny wpis ceny przez operatora. Jest to problem, którego druga część aplikacji wywołująca tę metodę nie może przewidzieć i nie mogę się po nim otrząsnąć. Jest BUG w Twojej bazie danych. Tak więc, i IllegalArguementException() powinny być w tym przypadku rzucone, które stwierdzą, że the price can't be negative.
Mam nadzieję, że wyraziłem się jasno..

 4
Author: Vishal K,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2013-03-04 19:06:19

Traktuj IllegalArgumentException jako warunki wstępne sprawdzaj i rozważaj zasadę projektowania: metoda publiczna powinna znać i publicznie dokumentować własne warunki wstępne.

Zgadzam się, że ten przykład jest poprawny:

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

Jeśli EmailUtil jest nieprzezroczysty , co oznacza, że jest jakiś powód, dla którego warunki wstępne nie mogą być opisane użytkownikowi końcowemu, to zaznaczony wyjątek jest poprawny. Druga wersja, poprawiona dla tego projektu:

import com.someoneelse.EmailUtil;

public void scanEmail(String emailStr, InputStream mime) throws ParseException {
    EmailAddress parsedAddress = EmailUtil.parseAddress(emailStr);
}

Jeśli EmailUtil jest przezroczysta , na przykład może to prywatna metoda należąca do danej klasy, IllegalArgumentException jest poprawna wtedy i tylko wtedy, gdy jej warunki wstępne mogą być opisane w dokumentacji funkcji. Jest to również poprawna wersja:

/** @param String email An email with an address in the form [email protected]
 * with no nested comments, periods or other nonsense.
 */
public String scanEmail(String email)
  if (!addressIsProperlyFormatted(email)) {
      throw new IllegalArgumentException("invalid address");
  }
  return parseEmail(emailAddr);
}
private String parseEmail(String emailS) {
  // Assumes email is valid
  boolean parsesJustFine = true;
  // Parse logic
  if (!parsesJustFine) {
    // As a private method it is an internal error if address is improperly
    // formatted. This is an internal error to the class implementation.
    throw new AssertError("Internal error");
  }
}

Ten projekt może pójść w obie strony.

  • jeśli warunki wstępne są kosztowne do opisania, lub jeśli klasa ma być używana przez klientów, którzy nie wiedzą, czy ich e-maile są ważne, użyj ParseException. Metoda najwyższego poziomu oto nazwa scanEmail, która podpowiada, że użytkownik końcowy zamierza wysłać niezabudowany e-mail, więc prawdopodobnie jest to poprawne.
  • jeśli warunki wstępne mogą być opisane w dokumentacji funkcji, a klasa nie zamierza wprowadzać nieprawidłowych danych wejściowych i dlatego jest wskazany błąd programisty, użyj IllegalArgumentException. Chociaż nie jest "zaznaczone", "sprawdzanie" przenosi się do Javadoc dokumentującego funkcję, do której Klient ma się stosować. IllegalArgumentException gdzie klient nie może powiedzieć, że ich argument jest nielegalny jest źle.

Notatka o IllegalStateException : oznacza to, że " wewnętrzny stan tego obiektu (prywatne zmienne instancji) nie jest w stanie wykonać tej akcji."Użytkownik końcowy nie może zobaczyć stanu prywatnego tak luźno mówiąc, że ma pierwszeństwo przed IllegalArgumentException w przypadku, gdy wywołanie klienta nie ma możliwości poznania, że stan obiektu jest niespójny. Nie mam dobrego wytłumaczenia, kiedy jest to preferowane niż zaznaczone wyjątki, chociaż rzeczy takie jak inicjalizacja dwa razy, lub utrata przykładami są połączenia z bazą danych, które nie są odzyskiwane.

 0
Author: djechlin,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2018-03-27 16:15:00