Quand une exception IllegalArgumentException doit-elle être levée?


Je crains qu'il s'agisse d'une exception d'exécution, elle devrait donc probablement être utilisée avec parcimonie.
Cas d'utilisation standard:

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

Mais cela semble forcer le design suivant:

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

Pour qu'il redevienne une exception vérifiée.

D'accord, mais allons-y avec ça. Si vous donnez une mauvaise entrée, vous recevrez une erreur d'exécution. Donc, tout d'abord, c'est en fait une politique assez difficile à mettre en œuvre uniformément, car vous pourriez avoir à faire le contraire conversion:

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

Et pire - lors de la vérification de 0 <= pct && pct <= 100 le code client pourrait être censé faire statiquement, ce n'est pas le cas pour des données plus avancées telles qu'une adresse e-mail, ou pire, quelque chose qui doit être vérifié par rapport à une base de données, donc en général le code client ne peut pas pré-valider.

Donc, fondamentalement, ce que je dis, c'est que je ne vois pas une véritable politique cohérente pour l'utilisation de IllegalArgumentException. Il semble qu'il ne devrait pas être utilisé et nous devrions nous en tenir à nos propres exceptions vérifiées. Qu'est ce qu'un bon cas d'utilisation pour jeter cela?

Author: APerson, 2013-03-04

6 answers

Le document api pour IllegalArgumentException est:

Lancé pour indiquer qu'une méthode a été passée un argument illégal ou inapproprié.

Regardant comment il est utilisé dans le jdk bibliothèques, je dirais:

  • Cela semble être une mesure défensive de se plaindre d'une entrée évidemment mauvaise avant que l'entrée ne puisse entrer dans les travaux et provoquer l'échec de quelque chose à mi chemin avec une erreur absurde message.

  • Il est utilisé dans les cas où il serait trop ennuyeux de lancer une exception vérifiée (bien qu'elle fasse une apparition dans java.lang.refléter le code, où la préoccupation concernant les niveaux ridicules de lancement d'exceptions vérifiées n'est pas autrement apparente).

J'utiliserais IllegalArgumentException pour faire la dernière vérification des arguments défensifs pour les utilitaires communs (en essayant de rester cohérent avec l'utilisation de jdk), où l'attente est qu'un mauvais argument est un erreur de programmeur, similaire à un NPE. Je ne l'utiliserais pas pour implémenter la validation dans le code métier. Je ne l'utiliserais certainement pas pour l'exemple d'e-mail.

 57
Author: Nathan Hughes, 2013-03-04 19:56:54

Lorsque vous parlez de "mauvaise entrée", vous devriez considérer d'où vient l'entrée.

Est l'entrée entrée par un utilisateur ou un autre système externe que vous ne contrôlez pas, vous devez vous attendre à ce que l'entrée soit invalide et la valider toujours. Il est parfaitement correct de lancer une exception vérifiée dans ce cas. Votre demande doit "récupérer" de cette exception en fournissant un message d'erreur à l'utilisateur.

Si l'entrée provient de votre propre système, par exemple votre base de données, ou d'un autre certaines parties de votre demande, vous devriez pouvoir compter sur elle pour être valide (elle aurait dû être validée avant d'y arriver). Dans ce cas, il est parfaitement correct de lancer une exception non cochée comme une exception IllegalArgumentException, qui ne devrait pas être attrapée (en général, vous ne devriez jamais attraper d'exceptions non cochées). C'est une erreur de programmeur que la valeur invalide est arrivée en premier lieu ;) Vous devez la corriger.

 19
Author: Tom, 2017-10-07 18:52:46

Lancer des exceptions d'exécution "avec parcimonie" n'est pas vraiment une bonne politique-Effective Java recommande d'utiliser des exceptions vérifiées lorsqueon peut raisonnablement s'attendre à ce que l'appelant récupère . (L'erreur du programmeur est un exemple spécifique: si un cas particulier indique une erreur du programmeur, vous devez lancer une exception non cochée; vous voulez que le programmeur ait une trace de pile de l'endroit où le problème logique s'est produit, ne pas essayer de le gérer vous-même.)

S'il n'y a pas d'espoir de guérison, alors n'hésitez pas à utiliser des exceptions non contrôlées; il ne sert à rien de les attraper, donc c'est parfaitement bien.

Il n'est pas clair à 100% de votre exemple dans quel cas cet exemple est dans votre code, cependant.

 10
Author: Louis Wasserman, 2013-03-04 18:40:07

Toute API doit vérifier la validité de chaque paramètre de toute méthode publique avant de l'exécuter:

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

Ils représentent 99,9% des erreurs de temps dans l'application car elle demande des opérations impossibles donc à la fin ce sont des bogues qui devraient planter l'application (c'est donc une erreur non récupérable).

Dans ce cas et en suivant l'approche de fail fast, vous devez laisser l'application se terminer pour éviter de corrompre l'état de l'application.

 5
Author: Ignacio Soler Garcia, 2015-12-17 11:47:12

Comme spécifié dans oracle official tutorial, il indique que:

Si l'on peut raisonnablement s'attendre à ce qu'un client se rétablisse d'une exception, faites - en une exception vérifiée. Si un client ne peut rien faire pour récupérer à partir de l'exception, faites-en une exception non cochée.

Si j'ai une Application interagissant avec la base de données en utilisant JDBC, Et j'ai une méthode qui prend l'argument comme int item et double price. Le price pour l'élément correspondant est lu à partir de table de base de données. Je multiplie simplement le nombre total de item achetés avec la valeur price et renvoie le résultat. Bien que je sois toujours sûr à ma fin (fin de l'application) que la valeur du champ de prix dans le tableau ne pourrait jamais être négative .Mais que se passe - t-il si la valeur du prix sort négative? Cela montre qu'il y a un problème sérieux avec le côté base de données. Peut-être une mauvaise entrée de prix par l'opérateur. C'est le genre de problème que l'autre partie de l'application appelant cette méthode ne peut pas anticiper et ne peut pas la récupérer. C'est un BUG dans votre base de données. Donc, et IllegalArguementException() devrait être jeté dans ce cas, ce qui indiquerait que the price can't be negative.
J'espère avoir clairement exprimé mon point de vue..

 4
Author: Vishal K, 2013-03-04 19:06:19

Traiter IllegalArgumentException comme conditions préalables vérifier, et de considérer le principe de conception: Une méthode publique doit à la fois connaître et documenter publiquement ses propres conditions.

Je conviens que cet exemple est correct:

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

Si EmailUtil est opaque, ce qui signifie qu'il y a une raison pour laquelle les conditions préalables ne peuvent pas être décrites à l'utilisateur final, alors une exception vérifiée est correcte. La deuxième version, corrigée pour cette conception:

import com.someoneelse.EmailUtil;

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

Si EmailUtil est transparent , par exemple c'est peut-être une méthode privée appartenant à la classe en question, IllegalArgumentException est correct si et seulement si ses conditions préalables peuvent être décrites dans la documentation de la fonction. Ceci est également une version correcte:

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

Cette conception pourrait aller dans les deux sens.

  • Si les conditions préalables sont coûteuses à décrire, ou si la classe est destinée à être utilisée par des clients qui ne savent pas si leurs e-mails sont valides, utilisez ParseException. La méthode de haut niveau voici nommé scanEmail qui laisse entendre que l'utilisateur final a l'intention d'envoyer un e-mail non étudié, donc c'est probablement correct.
  • Si des conditions préalables peuvent être décrites dans la documentation de la fonction, et que la classe n'a pas l'intention d'une entrée non valide et que, par conséquent, une erreur de programmeur est indiquée, utilisez IllegalArgumentException. Bien que non "cochée", la" vérification " se déplace vers le Javadoc documentant la fonction, à laquelle le client est censé adhérer. IllegalArgumentException lorsque le client ne peut pas dire que son argument est illégal à l'avance, c'est Faux.

Une note sur IllegalStateException: Cela signifie que "l'état interne de cet objet (variables d'instance privées) n'est pas en mesure d'effectuer cette action."L'utilisateur final ne peut pas voir l'état privé si vaguement parlant, il a priorité sur IllegalArgumentException dans le cas où l'appel client n'a aucun moyen de savoir que l'état de l'objet est incohérent. Je n'ai pas une bonne explication quand il est préféré aux exceptions vérifiées, bien que des choses comme l'initialisation deux fois, ou la perte d'un la connexion à la base de données qui n'est pas récupérée, sont des exemples.

 0
Author: djechlin, 2018-03-27 16:15:00