Est-il acceptable de lancer NullPointerException programmatiquement?

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

je pourrais le faire

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

mais les affirmations pouvaient être désactivées!

Alors, est-il normal de le faire

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 (comme NullReturnValueException ) pour une telle condition?

41
demandé sur Cœur 2010-07-24 01:46:42

19 réponses

Je ne vois aucun problème à lancer une NPE le plus tôt possible avant que la JVM ne le fasse pour vous - en particulier pour les arguments nuls. Il semble y avoir un certain débat à ce sujet, mais il y a de nombreux exemples dans les bibliothèques Java SE qui font exactement cela. Je ne vois pas pourquoi NPE devrait être saint dans l'aspect que vous n'êtes pas en mesure de le jeter vous-même.

cependant, je m'écarte. Cette question concerne quelque chose de différent. Vous parlez d'un post-condition déclarant que le la valeur de retour ne doit pas être nulle. Sûrement nul dans ce cas signifierait que vous avez un bug dans la méthode même ?

Comment pourrais-tu documenter ça? "Cette méthode lance une NullPointerException si la valeur de retour inopinément est null"? Sans expliquer comment cela a pu se produire? Non, je voudrais utiliser une assertion ici. Les Exceptions devraient être utilisées pour les erreurs qui peuvent éventuellement se produire - pas pour couvrir les choses qui peuvent se produire s'Il ya quelque chose de mal à l'intérieur de la méthode, parce que ne pas aider quelqu'un.

38
répondu waxwing 2010-07-24 23:10:16

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

la principale raison de ne pas le faire, comme Thorbjørn Ravn Andersen le dit dans un commentaire ci-dessous, est que vous ne voulez pas mélanger 'de vrais, mauvais NPE' avec des NPE lancés intentionnellement.

donc, jusqu'à ce que vous soyez sûr que vous êtes capable de reconnaître les NPE 'valides', je vous recommande d'utiliser IllegalArgumentException quand vous voulez dire à votre utilisateur D'API que null n'est pas une valeur d'argument valide. Votre le comportement de la méthode lorsque le paramètre null illégal passé doit être documenté.

une autre option (plus moderne imho) est d'utiliser @NotNull annotation près de l'argument. Voici un article sur l'utilisation de @NotNull annotation .

comme je l'ai mentionné plus tôt, il peut aussi y avoir des cas, lorsque lancer NPE ne sera pas déroutant ni pour vous ni pour vos coéquipiers: NPE cause doit être claire et reconnaissable.

pour par exemple, si vous utilisez une bibliothèque avec un module de conditions préalables , comme Guava , alors je trouve que l'utilisation de méthodes de type checkNotNull() est une meilleure façon de traiter les null illégalement passés.

checkNotNull(arg, msg) lance NPE, mais de la empattement il est assez clair, qu'il a été produit par Preconditions.checkNotNull() et donc ce n'est pas un bug inconnu, mais plutôt un comportement attendu.

59
répondu Roman 2013-02-18 11:37:27

étant donné que NullPointerException est la façon idiomatique de communiquer une valeur nulle inattendue en Java, je vous recommande de lancer un standard NullPointerException et non un standard maison. Gardez également à l'esprit que le principe de la moindre surprise suggérerait que vous n'inventez pas votre propre type d'exception pour un cas où un type d'exception système existe.

Affirmations sont bonnes pour le débogage, mais pas bon si vous avez à gérer certaines conditions, de sorte que n'est pas vraiment une bonne façon pour gérer la condition d'erreur.

27
répondu Timo Geusch 2010-07-23 21:49:57

le problème avec NullPointerException est, qu'il se produit quand vous oublier pour vérifier si quelque chose est nul ou donner 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 causée par le bogue dans le code, donc le lancer manuellement sera extrêmement déroutant pour la plupart d'entre eux. IllegalArgumentException est une meilleure idée quand vous passez argument inacceptable (tels que null, où quelque chose ne doit pas être null).

il déclenche aussi un autre heuristique. NPE = quelqu'un a fait une erreur dans le code ici, IllegalArgumentException = l'objet donné à la méthode est invalide.

d'un autre côté, le javadoc dit:

les applications doivent lancer des instances de cette classe pour indiquer

autres utilisations illégales de l'objet null .

So lancer NPE serait juridique , mais ce n'est pas la pratique courante, donc je recommande IllegalArgumentException .

12
répondu Danubian Sailor 2013-03-22 16:04:50

il n'y a certainement pas de loi universelle contre le fait de lancer NullPointerException, mais il est difficile de répondre si vous devriez réellement dans un tel exemple abstrait. Ce que vous ne voulez pas faire est de mettre les gens en haut de la chaîne dans la position d'essayer d'attraper NullPointerException. Code comme ceci (exemple réel, je le 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 un indicateur sûr que vous faites quelque chose de mal. Donc si la valeur de retour nulle est un indicateur de quelque État du système que vous êtes réellement capable de communiquer, utilisez une exception qui communique cet état. Il n'y a pas beaucoup de cas où je peux penser à où il est raisonnable de ne pas vérifier une référence juste pour jeter un nullpointer. Habituellement la toute prochaine ligne de code aurait jeté le nullpointer (ou quelque chose de plus informatif) de toute façon!

7
répondu Affe 2010-07-23 22:12:23

je considérerais que l'usage de NullPointerException ok, si vous vous souvenez de la description. C'est ce avec quoi la personne chargée de l'enquête travaille (les numéros de ligne peuvent changer). Rappelez-vous également de documenter que vos méthodes jettent des exceptions de pointeur null dans des cas spéciaux.

si vous vérifiez les paramètres de votre méthode dès le début, un throw new IllegalArgumentException("foo==null") est acceptable pour moi aussi.

5
répondu Thorbjørn Ravn Andersen 2010-07-23 23:00:18

Le JavaDoc pour NullPointerException : le

lancé lorsqu'une application tente de utilisez null dans un cas où un objet est requis. Il s'agit notamment de:

* 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

devraient lancer des instances de cette classe pour indiquer d'autres les utilisations de l'objet nul.

je considère la violation du post-condition comme un acte illégal. Cependant, Je pensez à l'exception que vous utilisez n'a pas beaucoup d'importance, parce que nous parlons d'un chemin de code qui devrait être (et est, espérons-le) inaccessible, et donc vous n'aurez 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 n'est jamais susceptible de voir.

si au contraire vous pensez que la condition post est susceptible d'être violée, il pourrait être une bonne idée d'inclure plus d'informations de débogage, comme les arguments avec lesquels la méthode a été invoquée.

3
répondu meriton 2010-07-23 22:10:57

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 retourner null . Mais ce n'est pas une exception NullPointerException. Si la valeur que vous devez retourner est null alors clairement l'appelant a soit donné de mauvais arguments ( IllegalArgumentException ), vous n'êtes pas dans un état valide ( IllegalStateException ), ou un autre beaucoup plus significatif exceptionnel condition s'est produite autre que NullPointerException (qui indique habituellement une erreur de programmation).

3
répondu Tim Bender 2010-07-24 06:32:21

http://pmd.sourceforge.net/pmd-5.0.1/rules/java/strictexception.html

"Évitez de lancer NullPointerExceptions. Ce sont déroutants parce que la plupart des gens supposeront que la machine virtuelle l'a lancé. Envisagez plutôt d'utiliser une exception ArgumentException illégale; cela sera clairement considéré comme une exception initiée par un programmeur."

3
répondu Gab 2017-06-29 11:56:42

un livre que j'ai appelé Java D'O'Reilly en un mot qui est écrit par un expert Liste cette définition pour NullPointerException:

signale une tentative d'accéder à un champ ou d'invoquer une méthode d'un objet nul.

puisque retourner null n'est ni l'un ni l'autre de ces choses, je pense qu'il serait plus approprié d'écrire votre propre exception.

1
répondu Rafe Kettler 2010-07-23 22:08:50

c'est souvent une très bonne idée de jeter NPE avant que la logique soit si profonde que le programmeur appelant aura du mal à comprendre ce qui était nul. les méthodes addListener () en sont un bon exemple.

en dépit des notes négatives non informées, il y a de nombreuses méthodes dans le JDK qui font exactement cela.

1
répondu user207421 2017-07-19 10:49:29

IMO vous ne devriez jamais lancer manuellement une NullPointerException. La routine d'appel ne saurait pas si la NullPointerException réelle ou manuelle sans vérifier la description. Dans ce cas, il semble que vous voudriez lancer votre propre exception qui correspond au problème plus près, de sorte que la méthode d'appel puisse récupérer correctement frm cette exception. Peut-être qu'une exception de postcondition serait assez générique pour de nombreuses circonstances.

0
répondu Jerod Houghtelling 2010-07-23 23:21:39

Java-verset null est toujours une valeur valide lorsque attend un objet. Vous feriez mieux d'éviter ces conditions de poste impossibles. Si vous ne pouvez vraiment pas supporter un null, alors vous devrez retravailler votre méthode pour pouvoir retourner une primitive.

0
répondu CurtainDog 2010-07-24 07:47:48

comme L'a dit Joshua Bloch: "Null craint!":) chaque fois qu'il y a la valeur null est mon visage, j'essaie d'utiliser l'Option que goyave fournit. Les avantages sont nombreux pour moi.

0
répondu Eugene 2013-02-18 11:40:53

absolument.

même JDK7 résoudre cela. 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
répondu Jin Kwon 2013-03-05 01:04:25

Lorsqu'il y a une post-condition, que 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 bug si la condition n'est pas remplie. La façon de l'exprimer en code est d'utiliser un assert à la post-condition. Lancer directement une exception, telle qu'une NullPointerException ou une IllegalStateException , serait un peu malavisé, et donc malavisé.

peut-on lancer NullPointerException programatiquement?

le doc Java API pour le NPE dit oui, mais, à en juger par les votes donnés sur cette page, une majorité de 3:1 développeurs dit non. Donc je dirais que ça dépend des conventions de votre groupe de travail.

le DOC API liste d'abord les cas où la JVM soulève une NPE parce que le code essaie d'invoquer une opération sur une référence nulle qui nécessite un objet de une sorte (comme appeler une méthode ou accéder à un champ), et null n'est pas un objet. Il dit ensuite:

Les Applications

devraient lancer des instances de cette classe pour indiquer d'autres utilisations illégales de l'objet null .

fait intéressant, 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 pointeurs. (Qui devrait ont probablement été NullReferenceException comme dans la bibliothèque de classe Microsoft.NET.)

donc devrions-nous rejeter le DOC de L'API pour ce motif? Je ne le pense pas. La bibliothèque de classe utilise les NPE comme décrit dans les docs, par exemple dans java.nio.channels :

sauf indication contraire, la transmission d'un argument null à un constructeur ou à une méthode de n'importe quelle classe ou interface dans ce paquet provoquera le lancement d'un NullPointerException .

il ne s'agit pas d'une NPE générée par la JVM, mais d'une NPE codée avec un message d'erreur joint indiquant quel argument était null (comme "in" is null! ). (On peut voir le code en faisant javap -c -p java.nio.channels.Channels | more , en cherchant private static void checkNotNull .) Et il existe de nombreuses classes qui utilisent les NPE de cette façon, essentiellement comme un cas spécial de IllegalArgumentException .

donc, après un peu d'enquête et de réflexion, je trouve que c'est une bonne utilisation de la NPE, et par conséquent, je suis d'accord avec L'API doc et la minorité de développeurs Java (selon les votes sur cette page) que vous avez à la fois le droit et le droit d'utiliser le NPE dans votre propre code de la même manière que la bibliothèque Java class le fait, c'est-à-dire en fournissant un message d'erreur, qui est ostensiblement absent des NPE générés par JVM, ce qui explique pourquoi il n'y a aucun problème à distinguer les deux types de NPE.

pour aborder le point mineur que le NPE sera jeté de toute façon plus loin sur la route: il peut très bien faire le bon sens pour attraper les erreurs tôt au lieu de permettre à la JVM de continuer avec le programme, en impliquant éventuellement disque ou L'E/S du réseau (et les retards), et en générant une trace de pile inutilement grande.

0
répondu Lumi 2014-02-03 13:21:56

Oui, c'est OK, mais je dirais que c'est une meilleure décision d' juste laisser faire .

le problème avec les programmeurs Java et null est que les gens viennent d'un arrière-plan C/C++, où NULL signifie quelque chose de très différent. Dans le déréférencement C / C++ Un pointeur NULL (ou wild) est un problème sérieux qui peut causer des problèmes de mémoire étranges ou planter votre programme (évident pas souhaitable). Si vous pouvez sortir de la façon de penser C/C++ et que vous réalisez que vous avez cette couche supplémentaire, la JVM, qui gère cette condition pour vous, vous commencez à penser à NULL un peu différemment.

dans C++ nous avons des références, par exemple, qui ne peuvent jamais être affectées NULL. En Java, il n'y a pas de références, mais les paramètres des objets Java se comportent plus comme des pointeurs C++. Mais il y a beaucoup de situations en Java dans lesquelles une méthode devrait implicitement et non recevoir une valeur nulle 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 aboutit à des vérifications null partout , alors qu'en C++ vous déclarez simplement une méthode pour prendre une référence, qui déclare explicitement qu'elle n'accepte pas NULL. Bientôt chaque méthode doit avoir un contrôle de santé mentale juste pour affirmer la condition du programme à ce point, créant un gâchis.

c'est un bien meilleur état d'esprit de travailler sous l'hypothèse que le contrat par défaut d'une méthode est que null n'est pas valide pour une valeur de paramètre.

pourquoi? Eh bien, regardons ce qui se passe quand une telle méthode reçoit null comme valeur de paramètre. a) peut-être que C'est OK parce qu'il ne déréférente pas la valeur en tant qu'élément 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 JVM est exactement ce que nous souhaitons: une exception est lancée indiquant que le contrat de la méthode a été violé en raison d'une valeur de paramètre étant nul, et il inclut une trace de pile nous amenant tout le chemin à la ligne dans la méthode où la valeur est utilisée de cette façon.

les gens sont en désaccord avec NPE parce qu'ils pensent que quand on voit NPE dans les journaux, ça veut dire"quelqu'un a merdé". Mais pensons à ce sujet pendant une seconde. Quelle est en fait la différence entre les NPE en tant qu'indicateur de raté et les comportements attendus? Je dirais que la différence majeure (et l'avantage) d'utiliser NPE comme le comportement attendu est qu'il pointe non pas à la méthode dans laquelle il s'est produit, mais à l'appelant pour violer le contrat de la méthode. C'est beaucoup plus informations utiles. Si nous devions simplement cocher null et jeter une exception différente, nous pourrions être sous la fausse impression que le comportement observé est une erreur attendue, quand vraiment l'appelant viole le contrat de la méthode. Félicitations, vous avez correctement anticipé comment vous l'appelant pourrait foirer en appelant la méthode-cependant tous vous avez fait est conduit vous - même égaré quant à ce que la cause réelle de l'exception est-ou au mieux, vous utilisez deux classes d'exception différentes pour indiquer la même chose et massivement salir le code avec des ordures inutiles dans l'intervalle.

donc quand il s'agit de cela les gens considèrent NPE comme un tabou. Littéralement les gens ne permettront pas qu'il soit jeté parce qu'Il ya un certain sentiment de honte qui va avec - comme si vous n'êtes pas assez intelligent parce que vous avez échoué à deviner où une valeur serait nulle. J'ai des nouvelles pour vous, vous écrivez juste plus de code 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();
}

^ politique différente. 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 économise quelques cycles CPU au détriment de beaucoup de code ennuyeux. Toutefois, nous faisons moins de comparaisons dans le deuxième 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 l'énoncé, plutôt qu'un cas d'exception 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();
}

^ utilisant la valeur de retour nulle pour indiquer l'absence d'une valeur. OK.

une autre raison pour laquelle les gens ont des problèmes avec les NPE est qu'ils ne savent pas comment gérer les exceptions. NPE ne devrait jamais être un show-stopper. Le comportement approprié est d'attraper RuntimeException, probablement à un plus haut (ou plus bas, selon la façon dont vous le voyez) le niveau dans la pile d'appels qui le piège et le signale avant "main". C'est-à-dire, en supposant que vous développez le genre de programme qui doit être plus résilient et ne peut pas juste crash quand un NPE se produit.

ligne de fond: ne vous attendez jamais à ce que ce soit une chose valide de passer en valeurs nulles pour les paramètres de la méthode. Et certainement ne pas créer un contrat pour une méthode qui accepte explicitement nulle et le traite comme un valeur valide. Mais, permet des exceptions null pointer à se produire, et laisser le code échouer, ou ne pas échouer quand il n'a pas d'importance, naturellement.

0
répondu Erich 2017-06-29 11:08:19

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

la question a été posée avant 7 ans, mais maintenant nous avons optionnel en java 8 et cette fonctionnalité permet d'empêcher NPE.

La dernière solution, qui est sur mon esprit, c'est que vous devriez vérifier objet à null et si elle est égale, alors jetez votre propre exception avec la description de ce qui s'est passé.

0
répondu Peter S. 2017-10-04 19:02:13

jeter cette exception n'est pas une bonne pratique dans certains cas et je me demande pourquoi quand vous l'attrapez déjà avec la déclaration si?

si(returnValue==null)

-1
répondu Truong Ha 2010-07-24 01:53:47