J'ai une méthode de définition simple pour une propriété et null
n'est pas appropriée pour cette propriété particulière. J'ai toujours été déchiré dans cette situation: dois-je lancer un IllegalArgumentException
ou un NullPointerException
? D'après les javadocs, les deux semblent appropriés. Existe-t-il une sorte de norme comprise? Ou est-ce juste une de ces choses que vous devez faire comme vous préférez et les deux sont vraiment correctes?
547
IllegalArgumentException
est en contradiction avec Java Objects.requireNonNull (T) et de goyave Preconditions.checkNotNull (T) qui jette unNullPointerException
. Cependant, la bonne réponse est définitivementIllegalArgumentException
comme expliqué dans l'excellente réponse de Jason Cohen et sa section de commentaires .Vous devez utiliser
IllegalArgumentException
(IAE) et nonNullPointerException
(NPE) pour les raisons suivantes:Premièrement, le NPE JavaDoc répertorie explicitement les cas où NPE est approprié. Notez que tous sont lancés par le runtime lorsqu'ils
null
sont utilisés de manière inappropriée. En revanche, l' IAE JavaDoc ne pourrait pas être plus clair: "Lancé pour indiquer qu'une méthode a été passée un argument illégal ou inapproprié." Ouais, c'est toi!Deuxièmement, lorsque vous voyez un NPE dans une trace de pile, que supposez-vous? Probablement que quelqu'un a déférencé a
null
. Lorsque vous voyez IAE, vous supposez que l'appelant de la méthode en haut de la pile a transmis une valeur illégale. Encore une fois, cette dernière hypothèse est vraie, la première est trompeuse.Troisièmement, comme IAE est clairement conçu pour valider les paramètres, vous devez le considérer comme le choix d'exception par défaut, alors pourquoi choisir NPE à la place? Certainement pas pour un comportement différent - vous attendez-vous vraiment à ce que l'appel de code intercepte les NPE séparément de l'IAE et fasse quelque chose de différent en conséquence? Essayez-vous de communiquer un message d'erreur plus spécifique? Mais vous pouvez quand même le faire dans le texte du message d'exception, comme vous le devriez pour tous les autres paramètres incorrects.
Quatrièmement, toutes les autres données de paramètres incorrectes seront IAE, alors pourquoi ne pas être cohérentes? Pourquoi un illégal
null
est-il si spécial qu'il mérite une exception distincte de tous les autres types d'arguments illégaux?Enfin, j'accepte l'argument donné par d'autres réponses selon lequel certaines parties de l'API Java utilisent NPE de cette manière. Cependant, l'API Java est incohérente avec tout, des types d'exception aux conventions de dénomination, donc je pense que copier aveuglément (votre partie préférée) de l'API Java n'est pas un argument suffisant pour l'emporter sur ces autres considérations.
la source
Validate.notNull
(commons lang) etPreconditions.checkNotNull
(goyave) lancent toutes deux NPE :-(checkArgument(arg != null)
, sans la commodité de renvoyer l'argument, ou vous pouvez créer un utilitaire local pour votre projet. " code.google.com/p/guava-libraries/wiki/IdeaGraveyardLa norme est de jeter le
NullPointerException
. L'infaillible "Java efficace", généralement infaillible, en discute brièvement dans l'article 42 (première édition), l'article 60 (deuxième édition) ou l'article 72 (troisième édition) "Favoriser l'utilisation d'exceptions standard":la source
J'étais tous en faveur de lancer
IllegalArgumentException
des paramètres nuls, jusqu'à aujourd'hui, quand j'ai remarqué lajava.util.Objects.requireNonNull
méthode en Java 7. Avec cette méthode, au lieu de faire:tu peux faire:
et il lancera un
NullPointerException
si le paramètre que vous passez estnull
.Étant donné que cette méthode est en plein dans le milieu de,
java.util
je considère que son existence est une indication assez forte que lancerNullPointerException
est "la manière Java de faire les choses".Je pense que je suis décidé en tout cas.
Notez que les arguments concernant le débogage dur sont faux car vous pouvez bien sûr fournir un message pour
NullPointerException
dire ce qui était nul et pourquoi il ne devrait pas l'être. Comme avecIllegalArgumentException
.Un avantage supplémentaire
NullPointerException
est que, dans un code hautement performant, vous pouvez vous passer d'une vérification explicite de null (etNullPointerException
d'un message d'erreur convivial), et vous fier uniquement à ceNullPointerException
que vous obtiendrez automatiquement lorsque vous appelez une méthode sur null paramètre. À condition d'appeler une méthode rapidement (c'est-à-dire d'échouer rapidement), alors vous avez essentiellement le même effet, mais pas tout à fait aussi convivial pour le développeur. La plupart du temps, il est probablement préférable de vérifier explicitement et de lancer avec un message utile pour indiquer quel paramètre était nul, mais il est agréable d'avoir la possibilité de le changer si les performances le dictent sans rompre le contrat publié de la méthode / constructeur.la source
Preconditions.checkNotNull(arg)
lance également des NPE.J'ai tendance à suivre la conception des bibliothèques JDK, en particulier les collections et la concurrence (Joshua Bloch, Doug Lea, ces gars-là savent concevoir des API solides). Quoi qu'il en soit, de nombreuses API du JDK lancent de manière proactive
NullPointerException
.Par exemple, le Javadoc pour les
Map.containsKey
états:Il est parfaitement valable de lancer votre propre NPE. La convention consiste à inclure le nom du paramètre qui était nul dans le message de l'exception.
Le modèle va:
Quoi que vous fassiez, n'autorisez pas une mauvaise valeur à être définie et lancez une exception plus tard lorsque d'autres codes tentent de l'utiliser. Cela fait du débogage un cauchemar. Vous devez toujours suivre le principe "fail-fast".
la source
A voté l'argument de Jason Cohen parce qu'il était bien présenté. Permettez-moi de le démembrer étape par étape. ;-)
Le NPE JavaDoc dit explicitement, "autres utilisations illégales de l'objet nul" . S'il était juste limité aux situations où le runtime rencontre un null alors qu'il ne devrait pas, tous ces cas pourraient être définis de manière beaucoup plus succincte.
Je ne peux pas l'aider si vous supposez la mauvaise chose, mais en supposant que l'encapsulation est appliquée correctement, vous ne devriez vraiment pas vous soucier ou remarquer si un null a été déférencé de manière inappropriée par rapport à si une méthode a détecté un null inapproprié et a déclenché une exception.
Je choisirais NPE plutôt que IAE pour plusieurs raisons
En fait, d'autres arguments non valides peuvent entraîner toutes sortes d'autres exceptions. UnknownHostException , FileNotFoundException , diverses exceptions d'erreur de syntaxe, IndexOutOfBoundsException , échecs d'authentification, etc., etc.
En général, je pense que NPE est très décrié car il est traditionnellement associé à du code qui ne suit pas le principe de l' échec rapide . Cela, plus l'échec du JDK à remplir les NPE avec une chaîne de message a vraiment créé un fort sentiment négatif qui n'est pas bien fondé. En effet, la différence entre NPE et IAE du point de vue de l'exécution est strictement le nom. De ce point de vue, plus vous êtes précis avec le nom, plus vous donnez de clarté à l'appelant.
la source
C'est une question de style "guerre sainte". En d'autres termes, les deux alternatives sont bonnes, mais les gens auront leurs préférences qu'ils défendront jusqu'à la mort.
la source
NullPointerException
devrait être jeté: c'est la convention que le JDK utilise et requiert pour les interfaces, c'est plus spécifique (commeIndexOutOfBoundsException
, etc.), etc.Si c'est une
setter
méthode qui luinull
est transmise, je pense qu'il serait plus logique de lancer unIllegalArgumentException
. UnNullPointerException
semble plus logique dans le cas où vous essayez réellement d'utiliser lenull
.Donc, si vous l' utilisez et est
null
,NullPointer
. Si elle est en cours de passé et il estnull
,IllegalArgument
.la source
Apache Commons Lang a une NullArgumentException qui fait un certain nombre des choses discutées ici: il étend IllegalArgumentException et son seul constructeur prend le nom de l'argument qui aurait dû être non nul.
Bien que je pense que lancer quelque chose comme une NullArgumentException ou IllegalArgumentException décrit plus précisément les circonstances exceptionnelles, mes collègues et moi avons choisi de nous en remettre aux conseils de Bloch à ce sujet.
la source
Je ne pourrais pas être plus d'accord avec ce qui se dit. Échec tôt, échec rapide. Très bon mantra d'exception.
La question de savoir quelle exception lancer est principalement une question de goût personnel. Dans mon esprit, IllegalArgumentException semble plus spécifique que l'utilisation d'un NPE car cela me dit que le problème est dû à un argument que j'ai passé à la méthode et non à une valeur qui peut avoir été générée lors de l'exécution de la méthode.
Mes 2 cents
la source
En fait, la question de lancer IllegalArgumentException ou NullPointerException n'est à mon humble avis qu'une "guerre sainte" pour une minorité ayant une compréhension incomlete de la gestion des exceptions en Java. En général, les règles sont simples et comme suit:
Il existe au moins trois très bonnes raisons contre le cas de mappage de toutes sortes de violations de contraintes d'argument à IllegalArgumentException, la troisième étant probablement assez grave pour marquer le mauvais style de la pratique:
(1) Un programmeur ne peut pas supposer en toute sécurité que tous les cas de violations de contraintes d'argument entraînent IllegalArgumentException, car la grande majorité des classes standard utilisent cette exception plutôt comme une corbeille à papier s'il n'y a pas de type d'exception plus spécifique disponible. Essayer de mapper tous les cas de violations de contraintes d'argument à IllegalArgumentException dans votre API ne fait que frustrer le programmeur en utilisant vos classes, car les bibliothèques standard suivent principalement des règles différentes qui violent la vôtre, et la plupart des utilisateurs de votre API les utiliseront également!
(2) Le mappage des exceptions entraîne en réalité un type d'anomalie différent, provoqué par l'héritage unique: toutes les exceptions Java sont des classes et ne prennent donc en charge que l'héritage unique. Par conséquent, il n'existe aucun moyen de créer une exception qui est vraiment dire à la fois une NullPointerException et une IllegalArgumentException, car les sous-classes ne peuvent hériter que de l'une ou de l'autre. Le lancement d'une exception IllegalArgumentException en cas d'argument nul rend donc plus difficile pour les utilisateurs de l'API de distinguer les problèmes chaque fois qu'un programme essaie de corriger le problème par programme, par exemple en introduisant des valeurs par défaut dans une répétition d'appel!
(3) Le mappage crée en fait le risque de masquage de bogues: pour mapper les violations de contraintes d'argument dans IllegalArgumentException, vous devrez coder un try-catch externe dans chaque méthode qui a des arguments contraints. Cependant, simplement attraper RuntimeException dans ce bloc catch est hors de question, car cela risque de mapper les RuntimeExceptions documentées levées par les méthodes de libery utilisées dans la vôtre dans IllegalArgumentException, même si elles ne sont pas causées par des violations de contraintes d'argument. Vous devez donc être très précis, mais même cet effort ne vous protège pas du cas où vous mappez accidentellement une exception d'exécution non documentée d'une autre API (c'est-à-dire un bogue) dans une exception IllegalArgumentException de votre API.
Avec la pratique standard d'un autre côté, les règles restent simples et les causes d'exception restent non masquées et spécifiques. Pour l'appelant de la méthode, les règles sont également simples: - si vous rencontrez une exception d'exécution documentée de quelque nature que ce soit parce que vous avez transmis une valeur illégale, répétez l'appel avec une valeur par défaut (car ces exceptions spécifiques sont nécessaires), ou corrigez votre code - si d'un autre côté vous rencontrez une exception d'exécution qui n'est pas documentée pour se produire pour un ensemble d'arguments donné, envoyez un rapport de bogue aux créateurs de la méthode pour vous assurer que leur code ou leur documentation est corrigée.
la source
La pratique acceptée consiste à utiliser IllegalArgumentException (String message) pour déclarer un paramètre non valide et donner le plus de détails possible ... Donc, pour dire qu'un paramètre a été trouvé nul alors que l'exception n'est pas nulle, vous feriez quelque chose comme ça:
Vous n'avez pratiquement aucune raison d'utiliser implicitement la "NullPointerException". NullPointerException est une exception levée par la machine virtuelle Java lorsque vous essayez d'exécuter du code sur une référence nulle (comme toString () ).
la source
Le lancement d'une exception exclusive aux
null
arguments (qu'il s'agisse d'NullPointerException
un type personnalisé ou non ) rend lesnull
tests automatisés plus fiables. Ce test automatisé peut être fait avec réflexion et un ensemble de valeurs par défaut, comme dans Goyave deNullPointerTester
. Par exemple,NullPointerTester
tenterait d'appeler la méthode suivante ...... avec deux listes d'arguments:
"", null
etnull, ImmutableList.of()
. Il testerait que chacun de ces appels lève l'attenduNullPointerException
. Pour cette implémentation, passer unenull
liste ne produit pasNullPointerException
. Il arrive cependant de produire unIllegalArgumentException
carNullPointerTester
just arrive d'utiliser une chaîne par défaut de""
. SiNullPointerTester
attend uniquementNullPointerException
pour lesnull
valeurs, il intercepte le bogue. S'il attendIllegalArgumentException
, il le manque.la source
Certaines collections supposent qu'il
null
est rejeté en utilisantNullPointerException
plutôt queIllegalArgumentException
. Par exemple, si vous comparez un ensemble contenantnull
à un ensemble qui rejettenull
, le premier ensemble fera appelcontainsAll
à l'autre et interceptera sonNullPointerException
- mais pasIllegalArgumentException
. (Je regarde la mise en œuvre deAbstractSet.equals
.)Vous pourriez raisonnablement affirmer que l'utilisation d'exceptions non contrôlées de cette manière est un contre-modèle, que la comparaison des collections qui contiennent
null
à des collections qui ne peuvent pas contenirnull
est un bogue probable qui devrait vraiment produire une exception, ou que mettrenull
une collection du tout est une mauvaise idée . Néanmoins, à moins que vous ne vouliez dire que celaequals
devrait lever une exception dans un tel cas, vous vous souvenez que celaNullPointerException
est nécessaire dans certaines circonstances mais pas dans d'autres. ("IAE avant NPE sauf après 'c' ...")la source
new TreeSet<>().containsAll(Arrays.asList((Object) null));
jetteNPE
parce que leList
contientnull
.En tant que question subjective, cela devrait être fermé, mais comme il est toujours ouvert:
Cela fait partie de la politique interne utilisée à mon ancien lieu de travail et cela a très bien fonctionné. Tout cela est de mémoire, donc je ne me souviens pas de la formulation exacte. Il convient de noter qu'ils n'ont pas utilisé d'exceptions vérifiées, mais cela dépasse le cadre de la question. Les exceptions non vérifiées qu'ils ont utilisées se répartissaient en 3 catégories principales.
NullPointerException: ne lancez pas intentionnellement. Les NPE doivent être lancés uniquement par la machine virtuelle lors du déréférencement d'une référence nulle. Tous les efforts possibles doivent être faits pour s'assurer que ceux-ci ne sont jamais jetés. @Nullable et @NotNull doivent être utilisés conjointement avec les outils d'analyse de code pour trouver ces erreurs.
IllegalArgumentException: levée lorsqu'un argument d'une fonction n'est pas conforme à la documentation publique, de sorte que l'erreur peut être identifiée et décrite en termes d'arguments transmis. La situation du PO tomberait dans cette catégorie.
IllegalStateException: levée lorsqu'une fonction est appelée et que ses arguments sont soit inattendus au moment où ils sont passés, soit incompatibles avec l'état de l'objet dont la méthode est membre.
Par exemple, il y avait deux versions internes de l'IndexOutOfBoundsException utilisées dans les choses qui avaient une longueur. Une sous-classe de IllegalStateException, utilisée si l'index était supérieur à la longueur. L'autre une sous-classe de IllegalArgumentException, utilisé si l'index était négatif. En effet, vous pouvez ajouter plus d'éléments à l'objet et l'argument serait valide, alors qu'un nombre négatif n'est jamais valide.
Comme je l'ai dit, ce système fonctionne très bien, et il a fallu quelqu'un pour expliquer pourquoi la distinction est là: "Selon le type d'erreur, il est assez simple pour vous de savoir quoi faire. Même si vous ne pouvez pas réellement comprendre ce qui n'a pas fonctionné, vous pouvez trouver où intercepter cette erreur et créer des informations de débogage supplémentaires. "
NullPointerException: gérez le cas Null ou insérez une assertion afin que le NPE ne soit pas levé. Si vous mettez une assertion, ce n'est qu'un des deux autres types. Si possible, continuez le débogage comme si l'assertion était là en premier lieu.
IllegalArgumentException: vous avez un problème sur votre site d'appel. Si les valeurs transmises proviennent d'une autre fonction, découvrez pourquoi vous recevez une valeur incorrecte. Si vous transmettez l'un de vos arguments, propagez l'erreur vérifie la pile d'appels jusqu'à ce que vous trouviez la fonction qui ne renvoie pas ce que vous attendez.
IllegalStateException: vous n'avez pas appelé vos fonctions dans le bon ordre. Si vous utilisez l'un de vos arguments, vérifiez-les et lancez une exception IllegalArgumentException décrivant le problème. Vous pouvez ensuite propager les joues contre la pile jusqu'à ce que vous trouviez le problème.
Quoi qu'il en soit, son point était que vous ne pouvez copier les IllegalArgumentAssertions que dans la pile. Il n'y a aucun moyen pour vous de propager les exceptions IllegalStateExceptions ou NullPointerExceptions dans la pile, car elles ont quelque chose à voir avec votre fonction.
la source
En général, un développeur ne doit jamais lever d'exception NullPointerException. Cette exception est levée par le runtime lorsque le code tente de déréférencer une variable dont la valeur est null. Par conséquent, si votre méthode veut explicitement interdire null, au lieu de simplement se produire qu'une valeur nulle déclenche une NullPointerException, vous devez lever une IllegalArgumentException.
la source
Je voulais distinguer les arguments Null d'autres arguments illégaux, j'ai donc dérivé une exception de l'IAE nommée NullArgumentException. Sans même avoir besoin de lire le message d'exception, je sais qu'un argument nul a été passé dans une méthode et en lisant le message, je découvre quel argument était nul. J'attrape toujours l'exception NullArgumentException avec un gestionnaire IAE, mais dans mes journaux, je peux voir la différence rapidement.
la source
la dichotomie ... Ne se chevauchent-ils pas? Seules les parties non superposées d'un ensemble peuvent faire une dichotomie. Comme je le vois:
la source
NullPointerException
ne ferait rien. La seule chose qui pourrait aider estIllegalNullPointerArgumentException extends IllegalArgumentException, NullPointerException
, mais nous n'avons pas d'héritage multiple.NullPointerException
levée lors de la tentative d'accès à un objet avec une variable de référence dont la valeur actuelle estnull
.IllegalArgumentException
levée lorsqu'une méthode reçoit un argument formaté différemment de ce que la méthode attend.la source
Selon votre scénario,
IllegalArgumentException
c'est le meilleur choix, car cenull
n'est pas une valeur valide pour votre propriété.la source
Idéalement, les exceptions d'exécution ne devraient pas être levées. Une exception vérifiée (exception métier) doit être créée pour votre scénario. Parce que si l'une de ces exceptions est levée et enregistrée, elle induit le développeur en erreur dans les journaux. Au lieu de cela, les exceptions métier ne créent pas cette panique et sont généralement ignorées lors du dépannage des journaux.
la source
Les définitions des liens vers les deux exceptions ci-dessus sont IllegalArgumentException: levées pour indiquer qu'une méthode a reçu un argument illégal ou inapproprié. NullPointerException: levée lorsqu'une application tente d'utiliser null dans le cas où un objet est requis.
La grande différence ici est que l'exception IllegalArgumentException est censée être utilisée lors de la vérification de la validité d'un argument d'une méthode. NullPointerException est censé être utilisé chaque fois qu'un objet est "utilisé" lorsqu'il est nul.
J'espère que cela aide à mettre les deux en perspective.
la source
Si c'est un "setter", ou quelque part que j'obtiens un membre à utiliser plus tard, j'ai tendance à utiliser IllegalArgumentException.
Si c'est quelque chose que je vais utiliser (déréférence) en ce moment dans la méthode, je lance une NullPointerException de manière proactive. J'aime mieux cela que de laisser le runtime le faire, car je peux fournir un message utile (il semble que le runtime puisse le faire aussi, mais c'est une diatribe pour un autre jour).
Si je remplace une méthode, j'utilise ce que la méthode substituée utilise.
la source
Vous devez lever une exception IllegalArgumentException, car cela rendra évident au programmeur qu'il a fait quelque chose de non valide. Les développeurs sont tellement habitués à voir NPE lancé par la machine virtuelle, que n'importe quel programmeur ne se rendrait pas immédiatement compte de son erreur et commencerait à regarder au hasard, ou pire, blâmerait votre code d'être `` bogué ''.
la source
Dans ce cas, IllegalArgumentException transmet des informations claires à l'utilisateur utilisant votre API que le "ne doit pas être nul". Comme d'autres utilisateurs du forum l'ont souligné, vous pouvez utiliser NPE si vous le souhaitez tant que vous transmettez les bonnes informations à l'utilisateur à l'aide de votre API.
GaryF et tweakt ont abandonné les références "Effective Java" (que je jure) qui recommandent d'utiliser NPE. Et regarder comment d'autres bonnes API sont construites est la meilleure façon de voir comment construire votre API.
Un autre bon exemple est de regarder les API Spring. Par exemple, org.springframework.beans.BeanUtils.instantiateClass (constructeur ctor, Object [] args) a une ligne Assert.notNull (ctor, "Constructor must not be null"). La méthode org.springframework.util.Assert.notNull (Object object, String message) vérifie si l'argument (objet) transmis est nul et s'il l'est, il lance une nouvelle IllegalArgumentException (message) qui est ensuite interceptée dans l'organisation. méthode springframework.beans.BeanUtils.instantiateClass (...).
la source
Si vous choisissez de lancer un NPE et que vous utilisez l'argument dans votre méthode, il peut être redondant et coûteux de rechercher explicitement un null. Je pense que la VM le fait déjà pour vous.
la source
NPE
mais les programmeurs s'exprimentIAE
devant la VM s'ils le souhaitent.