IllegalArgumentException ou NullPointerException pour un paramètre null? [fermé]

547

J'ai une méthode de définition simple pour une propriété et nulln'est pas appropriée pour cette propriété particulière. J'ai toujours été déchiré dans cette situation: dois-je lancer un IllegalArgumentExceptionou 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?

Mike Stone
la source

Réponses:

299

Il semble qu'un IllegalArgumentExceptionsoit demandé si vous ne voulez nullpas être une valeur autorisée, et le NullPointerExceptionserait levé si vous essayiez d' utiliser une variable qui se révèle être null.

Greg Hurlman
la source
33
Les réponses suivantes à cette question présentent des arguments convaincants selon lesquels NullPointerException est l'exception correcte: stackoverflow.com/a/8160/372926 ; stackoverflow.com/a/8196334/372926 ; et stackoverflow.com/a/6358/372926 .
SamStephens
2
IllegalArgumentExceptionest en contradiction avec Java Objects.requireNonNull (T) et de goyave Preconditions.checkNotNull (T) qui jette un NullPointerException. Cependant, la bonne réponse est définitivement IllegalArgumentException comme expliqué dans l'excellente réponse de Jason Cohen et sa section de commentaires .
matoni
417

Vous devez utiliser IllegalArgumentException(IAE) et non NullPointerException(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 nullsont 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 nullest-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.

Jason Cohen
la source
120
Java 2e édition effective, article 60: "On peut dire que toutes les invocations de méthodes erronées se résument à un argument illégal ou à un état illégal, mais d'autres exceptions sont généralement utilisées pour certains types d'arguments et d'états illégaux. Si un appelant passe null dans un paramètre pour lequel les valeurs nulles sont interdites, la convention stipule que NullPointerException doit être levée plutôt que IllegalArgumentException. De même, si un appelant transmet une valeur hors plage dans un paramètre représentant un index dans une séquence, IndexOutOfBoundsException doit être levée plutôt que IllegalArgumentException. "
Gili
33
Le JavaDoc pour NPE indique également ce qui suit: "Les applications doivent lancer des instances de cette classe pour indiquer d'autres utilisations illégales de l'objet null." Celui-ci pourrait être plus clair :(
R. Martinho Fernandes
12
Malheureusement, les méthodes de validation Validate.notNull(commons lang) et Preconditions.checkNotNull(goyave) lancent toutes deux NPE :-(
Aaron Digulla
2
Bien que Guava possède également Preconditions.checkArgument () lève IllegalArgumentException ...
michaelok
16
@AaronDigulla, de la documentation de Guava: "Nous réalisons qu'il existe de nombreux arguments valables en faveur de lancer IAE sur un argument nul. En fait, si nous avions une machine à remonter le temps> 15 ans, nous pourrions même essayer de pousser les choses dans Cependant, nous avons décidé de nous en tenir à la préférence JDK et Java efficace de NullPointerException. Si vous êtes fermement convaincu que IAE a raison, vous avez toujours 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/IdeaGraveyard
Arto Bendiken
162

La 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":

"On peut dire que toutes les invocations de méthodes erronées se résument à un argument illégal ou à un état illégal, mais d'autres exceptions sont généralement utilisées pour certains types d'arguments et d'états illégaux. Si un appelant passe null dans un paramètre pour lequel les valeurs nulles sont interdites, la convention stipule que NullPointerException soit levée plutôt que IllegalArgumentException. "

GaryF
la source
95
Je suis fortement en désaccord. NullPointerExceptions ne doit être levée que si la JVM suit accidentellement une référence nulle. C'est la différence qui vous aide lorsque vous êtes appelé pour regarder le code à 3 heures du matin.
Thorbjørn Ravn Andersen
26
Je ne suis pas nécessairement d'accord avec la norme (je pourrais en fait aller dans les deux sens sur la question), mais c'est ce que l'utilisation standard dans le JDK est, donc Java efficace le justifie. Je pense qu'il s'agit de choisir de suivre ou non la norme, ou de faire ce que vous pensez être juste. Sauf si vous avez une très bonne raison (et cela peut certainement être admissible), il est préférable de suivre la pratique standard.
GaryF
21
La trace d'exception montre le point de l'exception, donc si la différence dans le type de l'exception vous cause un enfer ou est "la différence qui vous aide", vous faites quelque chose de très mal.
Jim Balter
8
Fantasmes et sophismes. Juste en dessous, MB écrit "Notez que les arguments concernant le débogage dur sont faux car vous pouvez bien sûr fournir un message à NullPointerException disant ce qui était nul et pourquoi il ne devrait pas l'être. Tout comme avec IllegalArgumentException."
Jim Balter
10
En tant que répondeur original ici, permettez-moi de dire que cela n'a pas beaucoup d'importance. Cela ne garantit certainement pas 6 ans de conversation. Choisissez-en un, selon vos goûts, et soyez cohérent. Comme je l'ai souligné, la norme est le NPE. Si vous préférez IAE pour quelque raison que ce soit, allez-y. Soyez juste cohérent.
GaryF
138

J'étais tous en faveur de lancer IllegalArgumentExceptiondes paramètres nuls, jusqu'à aujourd'hui, quand j'ai remarqué la java.util.Objects.requireNonNullméthode en Java 7. Avec cette méthode, au lieu de faire:

if (param == null) {
    throw new IllegalArgumentException("param cannot be null.");
}

tu peux faire:

Objects.requireNonNull(param);

et il lancera un NullPointerExceptionsi le paramètre que vous passez est null.

Étant donné que cette méthode est en plein dans le milieu de, java.utilje considère que son existence est une indication assez forte que lancer NullPointerExceptionest "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 NullPointerExceptiondire ce qui était nul et pourquoi il ne devrait pas l'être. Comme avec IllegalArgumentException.

Un avantage supplémentaire NullPointerExceptionest que, dans un code hautement performant, vous pouvez vous passer d'une vérification explicite de null (et NullPointerExceptiond'un message d'erreur convivial), et vous fier uniquement à ce NullPointerExceptionque 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.

MB.
la source
14
La goyave Preconditions.checkNotNull(arg)lance également des NPE.
assylias
14
Cela n'ajoute pas vraiment plus de poids à NullPointerException pour les ARGUMENTS Nuls illégaux. Le JDK requireNonNull () et Guava checkNotNull () peuvent être appelés n'importe où dans le code, avec n'importe quel objet. Vous pouvez les appeler dans une boucle par exemple. requireNotNull () et checkNotNull () ne pouvaient pas supposer être invoqués avec certains arguments de méthode et lever IllegalArgumentException. Notez que Guava a également Preconditions.checkArgument () qui lève IllegalArgumentException.
Bogdan Calmac
2
Un point juste de Bogdan, bien que je soupçonne que l'utilisation typique (et généralement prévue) de requireNonNull est pour la vérification des arguments. Si vous aviez besoin de vérifier que quelque chose n'était pas nul dans une boucle, j'aurais pensé qu'une assertion serait la manière typique.
MB.
15
Je pense que le JavaDoc de Object.requireNonNull () ajoute du poids à l'argument: "Cette méthode est conçue principalement pour faire la validation des paramètres dans les méthodes et les constructeurs"
Richard Zschech
Gardez à l'esprit que l'argument des performances en faveur des contrôles nuls implicites est souvent invalide. Le JIT est capable de reconnaître les vérifications nulles de l'utilisateur et d'élider la vérification nulle implicite suivante, et / ou d'utiliser le même ensemble d'optimisations sur l'un ou l'autre type de vérification nulle. Voir ce wiki pour plus d'informations, en particulier: Les vérifications nulles écrites par l'utilisateur sont dans la plupart des cas fonctionnellement identiques à celles insérées par la JVM. Bien sûr, si vous faites quelque chose de plus sophistiqué dans votre null comme des messages personnalisés, cette optimisation peut ne pas s'appliquer.
BeeOnRope
70

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:

@throws NullPointerException si la clé est nulle et que cette carte n'autorise pas les clés nulles (facultatif).

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:

public void someMethod(Object mustNotBeNull) {  
    if (mustNotBeNull == null) {  
        throw new NullPointerException("mustNotBeNull must not be null");  
    }  
}

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".

Mark Renouf
la source
3
Matière à réflexion: La raison pour laquelle NullPointerException ne prolonge pas IllegalArgumentException est peut-être que la première peut se produire dans les cas n'impliquant pas d'arguments de méthode.
Gili
2
@Gili: ce problème existe peut-être en premier lieu parce que Java ne prend pas en charge l'héritage multiple. Si Java prend en charge MI, vous seriez en mesure de lever une exception qui hérite à la fois de IllegalArgumentException et de NullPointerException.
Lie Ryan
7
Le message n'a pas besoin d'inclure l'argument, car il serait toujours nul, donnant: "nul ne doit pas être nul", pas très utile. :-) Sinon, je suis d'accord, vous pouvez faire un NPE "riche", avec un message significatif.
PhiLho
5
Je dois accepter - suivez l'API standard en cas de doute. Tout n'est pas optimal dans l'API, mais il est toujours maintenu et itéré par des centaines de développeurs et utilisé par des millions de programmeurs. Maintenant, dans Java 7, nous avons un autre exemple de NPE utilisé de cette manière; la méthode Objects.requireNonNull (T obj) - clairement spécifiée pour vérifier que les références d'objet ne sont pas nulles, clairement spécifiée pour effectuer la validation des paramètres dans les méthodes / constructeurs, et clairement spécifiée pour lancer un NPE si l'objet est nul. Fin de
flamming_python
44

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

    • Il est plus précis sur la nature de l'opération illégale
    • La logique qui autorise par erreur les valeurs null a tendance à être très différente de la logique qui autorise par erreur les valeurs illégales. Par exemple, si je valide des données entrées par un utilisateur, si j'obtiens une valeur qui est inacceptable, la source de cette erreur est avec l'utilisateur final de l'application. Si j'obtiens un null, c'est une erreur de programmeur.
    • Des valeurs non valides peuvent entraîner des débordements de pile, des erreurs de mémoire insuffisante, des exceptions d'analyse, etc. En effet, la plupart des erreurs se présentent généralement, à un moment donné, comme une valeur non valide dans un appel de méthode. Pour cette raison, je vois IAE comme étant en fait le PLUS GÉNÉRAL de toutes les exceptions sous RuntimeException.
  • 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.

Christopher Smith
la source
La différence entre la plupart des exceptions non vérifiées n'est que le nom.
Thorbjørn Ravn Andersen
20

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.

Steve McLeod
la source
Non, il n'y a qu'une seule bonne réponse à cette question: utiliser l'exception throw IllegalArgument lorsque l'entrée de la méthode est incorrecte. Également dans un environnement de développement, vous pouvez utiliser des assertions pour vérifier la validité des entrées et
lever l'
@ Mr.Q Et je pense que cela NullPointerExceptiondevrait être jeté: c'est la convention que le JDK utilise et requiert pour les interfaces, c'est plus spécifique (comme IndexOutOfBoundsException, etc.), etc.
Solomon Ucko
kekekekkek ...: D
Yousha Aleayoub
17

Si c'est une setterméthode qui lui nullest transmise, je pense qu'il serait plus logique de lancer un IllegalArgumentException. Un NullPointerExceptionsemble plus logique dans le cas où vous essayez réellement d'utiliser le null.

Donc, si vous l' utilisez et est null, NullPointer. Si elle est en cours de passé et il est null, IllegalArgument.

Jeremy Privett
la source
9

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.

Brian T. Grant
la source
7
Notez qu'ils l'ont supprimé de commons-lang3: apache-commons.680414.n4.nabble.com/…
artbristol
7

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

Allain Lalonde
la source
7

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:

  • les violations de contraintes d'argument doivent être signalées le plus rapidement possible (-> échec rapide), afin d'éviter les états illégaux qui sont beaucoup plus difficiles à déboguer
  • en cas de pointeur nul invalide pour une raison quelconque, lancez NullPointerException
  • dans le cas d'un tableau / index de collection illégal, lancez ArrayIndexOutOfBounds
  • en cas de taille de tableau / collection négative, lancez NegativeArraySizeException
  • en cas d'argument illégal qui n'est pas couvert par ce qui précède et pour lequel vous n'avez pas d'autre type d'exception plus spécifique, lancez IllegalArgumentException en tant que corbeille à papier
  • d'autre part, en cas de violation de contrainte DANS UN CHAMP qui ne pourrait pas être évitée par un échec rapide pour une raison valable, interceptez et relancez comme IllegalStateException ou une exception vérifiée plus spécifique. Ne laissez jamais passer l'original NullPointerException, ArrayIndexOutOfBounds, etc. dans ce cas!

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.

Sascha Baumeister
la source
6

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:

if( variable == null )
    throw new IllegalArgumentException("The object 'variable' cannot be null");

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 () ).

Claude Houle
la source
6

Le lancement d'une exception exclusive aux nullarguments (qu'il s'agisse d' NullPointerExceptionun type personnalisé ou non ) rend les nulltests automatisés plus fiables. Ce test automatisé peut être fait avec réflexion et un ensemble de valeurs par défaut, comme dans Goyave de NullPointerTester. Par exemple, NullPointerTestertenterait d'appeler la méthode suivante ...

Foo(String string, List<?> list) {
  checkArgument(string.length() > 0);
  // missing null check for list!
  this.string = string;
  this.list = list;
}

... avec deux listes d'arguments: "", nullet null, ImmutableList.of(). Il testerait que chacun de ces appels lève l'attendu NullPointerException. Pour cette implémentation, passer une nullliste ne produit pasNullPointerException . Il arrive cependant de produire un IllegalArgumentExceptioncar NullPointerTesterjust arrive d'utiliser une chaîne par défaut de "". Si NullPointerTesterattend uniquement NullPointerExceptionpour les nullvaleurs, il intercepte le bogue. S'il attend IllegalArgumentException, il le manque.

Chris Povirk
la source
5

Certaines collections supposent qu'il nullest rejeté en utilisant NullPointerExceptionplutôt que IllegalArgumentException. Par exemple, si vous comparez un ensemble contenant nullà un ensemble qui rejette null, le premier ensemble fera appel containsAllà l'autre et interceptera son NullPointerException- mais pas IllegalArgumentException. (Je regarde la mise en œuvre de AbstractSet.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 contenir nullest un bogue probable qui devrait vraiment produire une exception, ou que mettre nullune collection du tout est une mauvaise idée . Néanmoins, à moins que vous ne vouliez dire que cela equalsdevrait lever une exception dans un tel cas, vous vous souvenez que cela NullPointerExceptionest nécessaire dans certaines circonstances mais pas dans d'autres. ("IAE avant NPE sauf après 'c' ...")

Chris Povirk
la source
Je ne vois pas comment le contient lance un NPE en fonction d'un élément à l'intérieur de la collection. La seule raison pour laquelle un NPE est lancé (afaict) est si la collection elle-même est nulle (dans ce cas, le NPE est lancé car il essaie d'accéder à son itérateur). Cela soulève cependant la question de savoir si l'entrée nulle doit être vérifiée ou si elle doit se propager jusqu'à ce qu'elle essaie d'accéder.
Alowaniak
2
new TreeSet<>().containsAll(Arrays.asList((Object) null));jette NPEparce que le Listcontient null.
Chris Povirk
1
Ah en effet, TreeSet # contient des lancers NPE "si l'élément spécifié est nul et que cet ensemble utilise un ordre naturel, ou si son comparateur ne permet pas les éléments null". Seulement regardé AbstractSet qui permet null, mon mauvais. Personnellement, je trouve ça bizarre, cela ne renvoie pas seulement faux, car dans ce cas, il ne peut pas y avoir de null ajouté.
Alowaniak
5

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.

Ben Seidel
la source
4

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
9
JavaDoc sur NPE a une autre opinion: "Les applications doivent lancer des instances de cette classe pour indiquer d'autres utilisations illégales de l'objet nul.". Ne soyez pas si catégorique
Donz
4

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.

Jason Fritcher
la source
J'ai adopté l'approche "throw new IllegalArgumentException (" foo == null ")". Vous devez de toute façon enregistrer le nom de la variable (pour être certain que vous regardez la bonne déclaration, etc.)
Thorbjørn Ravn Andersen
4

la dichotomie ... Ne se chevauchent-ils pas? Seules les parties non superposées d'un ensemble peuvent faire une dichotomie. Comme je le vois:

throw new IllegalArgumentException(new NullPointerException(NULL_ARGUMENT_IN_METHOD_BAD_BOY_BAD));
Luis Daniel Mesa Velasquez
la source
1
Cela doublerait les frais généraux pour la création d'exceptions et n'aiderait pas vraiment car la capture NullPointerExceptionne ferait rien. La seule chose qui pourrait aider est IllegalNullPointerArgumentException extends IllegalArgumentException, NullPointerException, mais nous n'avons pas d'héritage multiple.
maaartinus
Je pense que des exceptions plus spécifiques devraient être englobées par des exceptions plus générales. NPE est pour une expression tandis que IAE est pour une méthode. Comme les méthodes contiennent des instructions contenant des expressions, IAE est plus général.
Sgene9
Concernant les frais généraux, je n'en ai aucune idée. Mais puisque les stacktraces seraient fondamentalement identiques sauf que le nom de l'exception a changé au milieu, je pense qu'il ne devrait pas y avoir trop de surcharge pour les doubles exceptions. Si l'on s'inquiète de la surcharge, il peut utiliser des instructions "if" pour retourner un null ou -1 au lieu de lever une exception.
Sgene9
4

NullPointerExceptionlevée lors de la tentative d'accès à un objet avec une variable de référence dont la valeur actuelle est null.

IllegalArgumentException levée lorsqu'une méthode reçoit un argument formaté différemment de ce que la méthode attend.

Nitesh Soomani
la source
3

Selon votre scénario, IllegalArgumentExceptionc'est le meilleur choix, car ce nulln'est pas une valeur valide pour votre propriété.

Leo
la source
0

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.

vijay
la source
-1

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.

martinatime
la source
1
Le bit saillant est que c'est l' application qui utilise null, pas le runtime. Il existe donc un chevauchement assez important entre "lorsqu'une méthode a été passée un argument illégal ou inapproprié" et "lorsqu'une application utilise null". En théorie, si une application passe une valeur nulle pour un champ qui nécessite une valeur non nulle, les deux critères sont remplis.
Christopher Smith
-1

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.

erickson
la source
-1

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é ''.

Will Sargent
la source
4
Désolé, si un programmeur regarde autour de lui "au hasard" après avoir obtenu n'importe quel type d'exception ... changer le nom d'une exception ne va pas aider beaucoup.
Christopher Smith
-1

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
-5

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.

jassuncao
la source
Le temps d'exécution ne comprendra pas de msg significatif.
mP.
En fait, ce commentaire pourrait dériver une autre opinion. Laissez la VM s'exprimer, NPEmais les programmeurs s'expriment IAEdevant la VM s'ils le souhaitent.
Jin Kwon
1
Coûteux? Je ne pense pas que == null soit si cher ... De plus, l'argument null peut être simplement stocké pour une dernière utilisation et lèvera une exception longtemps après l'appel de méthode, ce qui rendra l'erreur plus difficile à suivre. Ou vous pouvez créer un objet coûteux avant d'utiliser l'argument null, etc. La détection précoce semble être une bonne option.
PhiLho
le vote à la baisse de cette réponse est une mauvaise compréhension du matériel derrière. Certes, les vérifications matérielles (que fait le CPU) sont moins chères que les vérifications explicites. Le déréférencement de null est un cas spécial SegmentationFault (SegV) (accès à une page n'appartenant pas au processus) que CPU / OS vérifie et JRE gère comme un cas spécial lançant NullPointerException.
digital_infinity