web-dev-qa-db-fra.com

Peut-on lancer NullPointerException par programme?

Quand il y a une post-condition, la valeur de retour d'une méthode ne doit pas être nulle, que peut-on faire? 

Je pourrais faire

assert returnValue != null : "Not acceptable null value";

mais les affirmations pourraient être désactivés!

Alors est-ce que ça va

if(returnValue==null)
      {
           throw new NullPointerException("return value is null at method AAA");
      }

?

Ou est-il préférable d'utiliser une exception définie par l'utilisateur (telle que NullReturnValueException) pour une telle condition?

41
stratwine

Je ne vois aucun problème à lancer un NPE le plus tôt possible avant que la JVM le fasse pour vous - en particulier pour les arguments nuls. Il semble y avoir un débat à ce sujet, mais il existe de nombreux exemples dans les bibliothèques Java SE qui font exactement cela. Je ne vois pas pourquoi les NPE devraient être saints du fait que vous ne pouvez pas le jeter vous-même.

Cependant, je m'égare. Cette question concerne quelque chose de différent. Vous parlez d'une post-condition indiquant que la valeur de retour ne doit pas être nulle. Dans ce cas, la valeur null signifierait sûrement que vous avez un bogue dans la méthode même ?

Comment pourriez-vous même documenter cela? "Cette méthode lève une exception NullPointerException si la valeur de retour inattendue est null"? Sans expliquer comment cela pourrait arriver? Non, je voudrais utiliser une affirmation ici. Les exceptions doivent être utilisées pour les erreurs qui peuvent éventuellement se produire - ne pas couvrir les choses qui peuvent se produire si quelque chose ne va pas dans la méthode, car cela n'aide personne.

39
waxwing

Je vous recommande de ne jamais jeter NullPointerException par vous-même. 

La principale raison de ne pas le faire, comme le dit Thorbjørn Ravn Andersen dans un commentaire ci-dessous, est que vous ne voulez pas mélanger les "vrais et mauvais NPE" aux NPE jetés intentionnellement.

Par conséquent, jusqu'à ce que vous sachiez que vous êtes en mesure de reconnaître un NPE "valide", nous vous recommandons d'utiliser IllegalArgumentException lorsque vous souhaitez indiquer à l'utilisateur de votre API que null n'est pas une valeur d'argument valide. Le comportement de votre méthode quand un paramètre nul illégal est passé doit être documenté.

Une autre option (plus moderne) consiste à utiliser l'annotation @NotNull près de l'argument . Voici un article sur l'utilisation de l'annotation @NotNull .

Comme je l'ai mentionné plus tôt, il peut également arriver que, lorsque lancer des NPE ne crée pas de confusion pour vous ou vos coéquipiers: La cause des NPE doit être claire et reconnaissable. 

Par exemple, si vous utilisez un module de bibliothèque avec des conditions préalables, tel que Guava, l'utilisation de méthodes de type checkNotNull()- est préférable pour traiter les valeurs NULL passées illégalement. 

checkNotNull(arg, msg) jette NPE, mais il est assez clair dans le stacktrace qu'il a été généré par Preconditions.checkNotNull() et qu'il ne s'agit donc pas d'un bogue inconnu, mais plutôt du comportement attendu.

59
Roman

Etant donné que NullPointerException est le moyen idiomatique de communiquer une valeur NULL inattendue en Java, je vous recommanderais de lancer une NullPointerException standard et non une valeur locale. Gardez également à l'esprit que le principe de la moindre surprise suggérerait de ne pas inventer votre propre type d'exception dans les cas où un type d'exception système existe.

Les assertions sont utiles pour le débogage, mais pas si vous devez gérer certaines conditions. Ce n'est donc pas vraiment un bon moyen de gérer la condition d'erreur.

27
Timo Geusch

Le problème avec NullPointerException est qu’il se produit lorsque vous oubliiez pour vérifier si quelque chose est nul ou donnez le mauvais argument qui est nul et ne devrait pas.

D'après mon expérience, les programmeurs Java apprennent très vite que cette exception est due au bogue dans le code. Par conséquent, le lancer manuellement sera extrêmement déroutant pour la plupart d'entre eux. IllegalArgumentException est une meilleure idée lorsque vous passez un argument inacceptable (tel que null, où quelque chose ne doit pas être nul).

Cela déclenche aussi une autre heuristique. NPE = quelqu'un a commis une erreur dans le code ici, IllegalArgumentException = l'objet donné à la méthode n'est pas valide.

Par ailleurs, le javadoc raconte:

Les applications doivent renvoyer des instances de cette classe pour indiquer
autres utilisations illégales de l'objet null.

Ainsi, lancer des NPE serait legal, mais ce n’est pas une pratique courante, aussi je recommanderais IllegalArgumentException.

12
Danubian Sailor

Il n’existe certainement pas de loi universelle contre les exceptions NullPointerException, mais il est difficile de répondre si vous le devriez réellement dans un exemple aussi abstrait. Ce que vous ne voulez pas faire, c'est mettre les gens dans la chaîne dans la position d'essayer d'attraper NullPointerException. Code comme ceci (exemple réel, je jure):

catch (NullPointerException npe) {
  if (npe.getMessage().equals("Null return value from getProdByCode") {
    drawToUser("Unable to find a product for the product type code you entered");
  } 
}

Est-ce un indicateur infaillible que vous faites quelque chose de mal? Ainsi, si la valeur de retour NULL est un indicateur de l'état du système que vous êtes en mesure de communiquer, utilisez une exception qui communique cet état. Il n'y a pas beaucoup de cas où je peux penser à où il est judicieux de vérifier une référence de manière à ce qu'il ne soit rien d'autre que de jeter un pointeur à zéro. D'habitude, la toute prochaine ligne de code aurait jeté le nullpointer (ou quelque chose de plus informatif) de toute façon!

7
Affe

Je considérerais que l’utilisation de NullPointerException ok, si vous vous souvenez de la description. C’est ce avec quoi l’enquêteur travaille (les numéros de ligne peuvent changer). Pensez également à documenter que vos méthodes génèrent des exceptions de pointeur nul dans des cas particuliers.

Si vous vérifiez les paramètres de votre méthode dès le début, une throw new IllegalArgumentException("foo==null") me convient également.

5

Le JavaDoc pour NullPointerException states:

Lancé quand une application tente de utilisez null dans le cas où un objet est Champs obligatoires. Ceux-ci inclus:

* Calling the instance method of a null object.
* Accessing or modifying the field of a null object.
* Taking the length of null as if it were an array.
* Accessing or modifying the slots of null as if it were an array.
* Throwing null as if it were a Throwable value. 

Les applications doivent renvoyer des instances de cette classe pour indiquer d'autres illégaux utilise de l'objet null.

Je considère que violer la post-condition est une action illégale. Cependant, je pense que l'exception que vous utilisez importe peu, car nous parlons d'un chemin de code qui devrait être inaccessible (et si tout va bien), et vous n'aurez donc pas de traitement d'erreur spécifique à cette exception, et donc le seul effet de ce nom est une formulation différente d’une entrée dans un fichier journal que personne ne verra jamais.

Si, au contraire, vous pensez que la condition de publication est susceptible d'être violée, il peut être judicieux d'inclure davantage d'informations de débogage, telles que les arguments avec lesquels la méthode a été invoquée.

3
meriton

http://pmd.sourceforge.net/pmd-5.0.1/rules/Java/strictexception.html
"Évitez de lancer des exceptions NullPointerExceptions. C’est déroutant, car la plupart des gens vont supposer que la machine virtuelle l’a lancée. Envisagez plutôt d’utiliser une exception IllegalArgumentException; elle sera clairement considérée comme une exception déclenchée par le programmeur."

3
Gab

Si vous décrivez un contrat de méthode dont la valeur de retour ne peut pas être null, vous feriez mieux de vous assurer de ne pas renvoyer null. Mais ce n'est pas du tout une exception NullPointerException. Si la valeur que vous devez renvoyer est null, alors clairement l'appelant vous a fourni de mauvais arguments ( IllegalArgumentException ), vous n'êtes pas dans un état valide ( IllegalStateException ) ou une autre condition exceptionnelle beaucoup plus significative s'est produite autre que NullPointerException (qui indique généralement une erreur de programmation).

3
Tim Bender

Un livre que j'ai appelé Java in A Nutshell d'O'Reilly qui est écrit par un expert répertorie cette définition pour NullPointerException:

Signale une tentative d'accéder à un champ ou d'appeler une méthode d'un objet null.

Étant donné que renvoyer null n'est pas l'une de ces choses, je pense qu'il serait plus approprié d'écrire votre propre exception.

1
Rafe Kettler

C'est souvent une très bonne idée de lancer NPE avant que la logique ne devienne si profonde que le programmeur appelant aura du mal à déterminer ce qui était nul. Les méthodes addListener () en sont un bon exemple. 

Malgré des votes positifs non informés, il existe de nombreuses méthodes dans le JDK qui font exactement cela.

1
user207421

Absolument oui.

Même JDK7 résout ce problème. Voir Objets # requireNonNull

void doWith(final Object mustBeNotNull) {

    /*
    // bush style
    if (mustBeNotNull == null) {
        throw new IllegalArgumentException("mustBeNotNull must not be null");
    }
    */

    /*
    // obama style
    if (mustBeNotNull == null) {
        throw new NullPointerException("mustBeNotNull must not be null");
    }
    */

    // kangnam style
    Objects.requireNonNull(mustBeNotNull, "mustBeNotNull must not be null");

    assert mustBeNotNull != null;
}
0
Jin Kwon

Dans le verset Java, null est toujours une valeur valide pour l'attente d'un objet. Vous feriez mieux d'éviter de telles conditions de poste impossibles. Si vous ne pouvez vraiment pas respecter un null, vous devrez retravailler votre méthode pour pouvoir renvoyer une primitive.

0
CurtainDog

Je suis d'accord avec l'affirmation dans les réponses précédentes, que le NPE est un bogue dans le code et ne devrait pas être jeté, mais le développeur devrait corriger inattendue null. Cependant, cet état peut être évité la plupart du temps par des tests. 

La question a été posée avant 7 ans, mais nous avons maintenant optionnel en Java 8 et cette fonctionnalité permet d’empêcher les NPE. 

La dernière solution, qui me tient à l’esprit, c’est que vous devriez vérifier objet sur null et s’il est égal, lancez donc votre propre exception en décrivant ce qui s’est passé.

0
Peter S.

Comme Joshua Bloch a dit un jour: "Null sucks!" :) chaque fois qu'il y a null est mon visage, j'essaie d'utiliser le facultatif fourni par goyave. Les avantages sont nombreux pour moi.

0
Eugene

Oui, c’est bien, mais je dirais que c’est une meilleure décision de laissons simplement cela se produire .

Le problème avec les programmeurs Java et null est que les gens viennent d’un contexte C/C++, où NULL signifie quelque chose de très différent. En C/C++, la déréférence d'un pointeur NULL (ou wild) est un problème grave qui peut entraîner d'étranges problèmes de mémoire ou faire planter votre programme (cela n'est évidemment pas souhaitable). Si vous parvenez à vous écarter de la mentalité C/C++ et réalisez que vous disposez de cette couche supplémentaire, la JVM, qui gère cette condition pour vous, vous commencez à penser à NULL un peu différemment.

En C++, nous avons des références, par exemple, auxquelles on ne peut jamais attribuer la valeur NULL. En Java, il n'y a pas de références, mais les paramètres d'objet Java se comportent davantage comme des pointeurs C++. Mais il existe de nombreuses situations en Java dans lesquelles une méthode doit implicitementPASrecevoir une valeur null pour un paramètre! Alors que faisons-nous?

Le problème avec le traitement de null en Java, comme vous le faites en C++, est que cela entraîne des contrôles nulsPARTOUT, alors qu'en C++, vous déclareriez simplement une méthode pour prendre une référence, ce qui indique explicitement qu'elle n'accepte pas. NUL. Très vite, chaque méthode doit faire l’objet d’une vérification de la santé mentale afin d’affirmer l’état du programme à ce moment-là, ce qui crée un désastre.

C'est un bien meilleur état d'esprit de travailler en supposant que le contrat par défaut d'une méthode est que null est invalide pour une valeur de paramètre.

Pourquoi? Voyons ce qui se passe quand une telle méthode reçoit la valeur null en tant que valeur de paramètre. a) Peut-être que c'est correct parce que cela ne déréférence pas la valeur dans le cadre de son comportement. Dans ce cas, rien ne se passe. b) La valeur est déréférencée. Dans ce cas, le comportement de la machine virtuelle Java correspond exactement à ce que nous souhaitons: une exception est levée, indiquant que le contrat de la méthode a été violé en raison de la valeur null du paramètre, et il inclut une trace de pile nous amenant jusqu'au ligne dans la méthode où la valeur est utilisée de cette façon.

Les gens ne sont pas d'accord avec NPE parce qu'ils pensent que, lorsque vous voyez NPE dans les journaux, cela signifie "quelqu'un de merde". Mais réfléchissons-y une seconde. Quelle est la différence entre les NPE en tant qu'indicateur de corruption et de comportement attendu? Je dirais que la principale différence (et l'avantage) de l'utilisation de NPE en tant que comportement attendu est qu'elle ne pointe pas sur la méthode dans laquelle elle s'est produite, mais sur l'appelant pour violation du contrat de la méthode. Ce sont des informations beaucoup plus utiles. Si nous devions simplement vérifier null et renvoyer une exception différente, nous pourrions avoir la fausse impression que le comportement observé est une erreur attendue, alors que l'appelant enfreint réellement le contrat de la méthode. Félicitations, vous avez correctement prévu comment l'appelant pourrait bousiller l'appel de la méthode. Cependant, tout ce que vous avez fait est de vous égarer quant à la cause réelle de l'exception - ou au mieux, vous utilisez deux classes d'exceptions différentes. pour indiquer la même chose et en salissant massivement le code avec des ordures inutiles dans l'intervalle.

Donc, quand on en vient à cela, les gens considèrent le NPE comme un sujet tabou. Les gens refusent littéralement que cela soit lancé, car il y a un sentiment de honte qui va avec - comme si vous n'étiez pas assez intelligent, parce que vous n'aviez pas deviné où une valeur serait nulle. Eh bien, j'ai des nouvelles pour vous les gars, vous écrivez juste un code plus inutile pour faire la même chose.

Quelques exemples:

public void foo(Object o) {
  if (o == null) {
    throw new IGotchaException("HA! You're an IDIOT! I knew it!!");
  }
  o.bar();
}

public void foo(Object o) {
  o.bar();
}

^ Politiquement différent. Fonctionnellement, pas tellement.

public void foo(int a, long b, double c, Object o) {
  if (o == null) {
    throw new IllegalArgumentException("Oh. Uh. Well, you've passed me null here. I... I'm not sure where to go from here because this object is kind of required for this function to do what it's supposed to do. Soooo... wouldja mind reworking your code a little bit so as to not pass null to this function as a parameter?! That'd be great thanks. Oh by the way, it's cause we deference o 40 lines below here");
  }
  // ...
  o.doSomethingWithA(a);
}

public void foo(int a, long b, double c, Object o) {
  // ...
  o.doSomethingWithA(a);
  // NullPointerException, line 40, e.g. it wasn't OK to pass null for o you lunkhead
}

^ Peut-être enregistre quelques cycles de processeur au détriment de beaucoup de code ennuyeux. Cependant, nous faisons moins de comparaisons dans le second cas.

public void foo(Object a, Object b, Object c, Object d) {
  if (a == null) throw IllegalArgumentException("jackass");
  if (b == null) throw IllegalArgumentException("jackass");
  if (c == null) throw IllegalArgumentException("jackass");
  // But d is totally OK!
  // ...
  c.setSomeValueThatMayBeNull(d);
}

public void foo(Object a, Object b, Object c, Object d) {
  // ...
  c.setSomeValueThatMayBeNull(d);
  // Throws null pointer exception if c is null, but not if d is null. Which is basically the same as above
}

^ Le contrat est implicite à partir de la déclaration, plutôt qu'un cas exceptionnel au début de la méthode. N'offre aucun autre inconvénient.

public void foo(Object o) {
  if (o == null) {
    doTheBoogie();
  } else {
    doTheRobot();
  }
}

^ Mauvais

public void foo(Object o, int b) {
  Bar value = o.findSomethingWhichMayExist(b);
  if (value == null)
    return;
  value.doSomething();
}

^ Utilisation d'une valeur de retour nulle pour indiquer l'absence d'une valeur. D'ACCORD.

Une autre raison pour laquelle les utilisateurs ont des problèmes avec NPE est qu’ils ne savent pas comment gérer les exceptions. Les NPE ne devraient jamais être un obstacle. Le comportement approprié consiste à intercepter RuntimeException, probablement à un niveau beaucoup plus élevé (ou inférieur, selon votre perception) dans la pile d'appels qui l'intercepte et la signale avant "principal". En d’autres termes, si vous développez le type de programme qui doit être plus résilient et ne peut pas simplement planter / lorsqu’un NPE se produit.

En bout de ligne: ne vous attendez jamais à ce que ce soit une chose valide de transmettre des valeurs NULL pour les paramètres de méthode. Et surtout, ne créez pas de contrat pour une méthode qui accepte explicitement null et la traite comme une valeur valide. Mais, autorise null des exceptions de pointeur, et laisse le code échouer, ou ne pas échouer lorsque cela n'a pas d'importance, naturellement.

0
Erich

OMI, vous ne devriez jamais lancer manuellement une exception NullPointerException. La routine d'appel ne saurait pas savoir s'il s'agit d'une exception NullPointerException réelle ou manuelle sans vérifier la description. Dans ce cas, il semble que vous souhaitiez lancer votre propre exception correspondant au problème, afin que la méthode appelante puisse récupérer correctement cette exception. Peut-être qu'une exception PostConditionException serait assez générique pour de nombreuses circonstances. 

0
Jerod Houghtelling

Quand il y a une post-condition, la valeur de retour d'une méthode ne doit pas être nulle, que peut-on faire?

Une post-condition signifie que la méthode en question a un bogue si la condition n'est pas remplie. La façon de l'exprimer dans le code consiste à utiliser une variable assert dans la post-condition. Le fait d'exécuter directement une exception, telle qu'une NullPointerException ou une IllegalStateException, serait un peu peu judicieux et, partant, erroné.

Est-il possible de lancer NullPointerException par programme?

La documentation relative à l'API Java pour le NPE dit oui, mais, à en juger par les votes donnés sur cette page, une majorité de développeurs 3: 1 dit non. Je dirais donc que cela dépend des conventions de votre groupe de travail.

La documentation API répertorie d'abord les cas dans lesquels la machine virtuelle Java crée un NPE, car le code tente d'appeler une opération sur une référence null nécessitant un objet quelconque (comme appeler une méthode ou accéder à un champ), et null n'est pas un objet. Il déclare ensuite:

Les applications doivent utiliser des instances de cette classe pour indiquer d'autres utilisations illégales de l'objet null.

Il est intéressant de noter que null est appelé un "objet" ici, ce qui n'est pas le cas. Ce qui me rappelle que le nom même NullPointerException est bizarre pour un langage qui n'a pas de pointeur. (Cela aurait probablement dû être NullReferenceException comme dans la bibliothèque de classes Microsoft .NET.)

Alors, devrions-nous rejeter la documentation de l'API sur ce point? Je ne pense pas. La bibliothèque de classes utilise les NPE comme décrit dans la documentation, par exemple dans Java.nio.channels:

Sauf indication contraire, le passage d'un argument null à un constructeur ou à une méthode de toute classe ou interface de ce package provoquera l'envoi d'une NullPointerException.

Ce n'est pas un NPE généré par la machine virtuelle Java, mais un NPE codé avec un message d'erreur joint indiquant quel argument était null (comme "in" is null!). (Le code peut être vu en effectuant javap -c -p Java.nio.channels.Channels | more, en recherchant private static void checkNotNull.) De nombreuses classes utilisent les NPE de cette manière, essentiellement dans le cas spécial de IllegalArgumentException.

Donc, après avoir étudié un peu cela et réfléchi, je trouve que cela constitue un bon usage du NPE, et je suis donc d’accord avec le doc de l’API et la minorité de développeurs Java (selon les votes sur cette page) que vous êtes tous les deux droit et droit d'utiliser le NPE dans votre propre code de la même manière que la bibliothèque de classes Java, c’est-à-dire en fournissant un message d’erreur, qui manque visiblement aux NPE générés par la JVM. C’est pourquoi il n’ya aucun problème à dire les deux types de NPE. une part.

Pour répondre au point mineur selon lequel le NPE sera de toute façon plus avancé: il peut être judicieux de détecter les erreurs plus tôt que prévu, au lieu de laisser la JVM poursuivre le programme, ce qui peut impliquer des E/S de disque ou de réseau (et des retards). ) et générer une trace de pile inutilement grande.

0
Lumi