Question

Si je reçois une exception NullPointerException dans un appel comme celui-ci:

someObject.getSomething().getSomethingElse().
    getAnotherThing().getYetAnotherObject().getValue();

Je reçois un texte d'exception plutôt inutile comme:

Exception in thread "main" java.lang.NullPointerException
at package.SomeClass.someMethod(SomeClass.java:12)

Je trouve assez difficile de savoir quel appel retourne réellement à null, me retrouvant souvent à refactoriser le code pour obtenir quelque chose comme ceci:

Foo ret1 = someObject.getSomething();
Bar ret2 = ret1.getSomethingElse();
Baz ret3 = ret2.getAnotherThing();
Bam ret4 = ret3.getYetAnotherOject();
int ret5 = ret4.getValue();

et ensuite attendre une exception NullPointerException plus descriptive qui me dit quelle ligne rechercher.

Certains d’entre vous pourraient dire que concaténer des getters est un mauvais style et doit être évité de toute façon, mais ma question est la suivante: puis-je trouver le bogue sans changer le code?

Astuce: J'utilise eclipse et je sais ce qu'est un débogueur, mais je ne peux pas comprendre comment l'appliquer au problème.

Ma conclusion sur les réponses:
Certaines réponses m'ont dit que je ne devrais pas enchaîner les getters l'un après l'autre, d'autres m'ont montré comment déboguer mon code si je désobéissais à ce conseil.

J'ai accepté une réponse qui m’a appris de façon précise quand enchaîner les getters:

  • S'ils ne peuvent pas renvoyer null, enchaînez-les aussi longtemps que vous le souhaitez. Pas besoin de vérifier! = Null, pas besoin de s'inquiéter de NullPointerExceptions ( soyez averti que l'enchaînement reste conforme à la loi de Demeter, mais je peux vivre avec ça )
  • S'ils peuvent renvoyer null, ne les enchaînez jamais et effectuez une vérification des valeurs NULL pour chacune d'elles pouvant renvoyer null

Cela rend tout bon conseil sur le débogage réel inutile.

Était-ce utile?

La solution

La réponse dépend de votre façon de voir (le contrat de) vos accesseurs. S'ils peuvent renvoyer null , vous devriez vraiment vérifier la valeur de retour à chaque fois. Si le getter ne doit pas renvoyer null , il doit contenir une vérification et émettre une exception ( IllegalStateException ?) Au lieu de retourner null , afin que promis de ne jamais revenir. Le stacktrace vous indiquera le getter exact. Vous pouvez même mettre l'état inattendu que votre getter a trouvé dans le message d'exception.

Autres conseils

NPE est l'exception la plus inutile en Java, période. Il semble être toujours implémenté avec lenteur et ne dit jamais exactement ce qui l’a provoquée, même aussi simple que "class x.y.Z est null". aiderait beaucoup à déboguer de tels cas.

Quoi qu'il en soit, le seul moyen efficace de trouver le lanceur NPE dans ces cas-là est le type de refactoring suivant:

someObject.getSomething()
          .getSomethingElse()
          .getAnotherThing()
          .getYetAnotherObject()
          .getValue();

Voilà, NPE pointe maintenant sur la ligne correcte et donc sur la méthode correcte qui renvoie le NPE réel. La solution n’est pas aussi élégante que je le souhaiterais, mais cela fonctionne.

Dans IntelliJ IDEA, vous pouvez définir des points d'exception . Ces points d'arrêt se déclenchent chaque fois qu'une exception spécifiée est levée (vous pouvez l'étendre à un package ou à une classe).

Ainsi, il devrait être facile de trouver la source de votre NPE.

Je suppose que vous pouvez faire quelque chose de similaire dans Netbeans ou Eclipse.

EDIT: Ici , explique comment ajouter un point de cassure d'exception dans eclipse

Si vous vous trouvez souvent en train d'écrire:

a.getB().getC().getD().getE();

il s’agit probablement d’une odeur de code à éviter. Vous pouvez par exemple refactoriser dans a.getE () qui appelle b.getE () qui appelle c.getE () d.getE () . (Cet exemple peut ne pas avoir de sens pour votre cas d'utilisation particulier, mais c'est un modèle pour corriger cette odeur de code.)

Voir aussi la loi de Demeter , qui dit:

  • Votre méthode peut appeler directement d'autres méthodes de sa classe
  • Votre méthode peut appeler des méthodes directement sur ses propres champs (mais pas sur les champs des champs)
  • Lorsque votre méthode prend des paramètres, elle peut appeler des méthodes directement sur ces paramètres.
  • Lorsque votre méthode crée des objets locaux, cette méthode peut appeler des méthodes sur les objets locaux.

Par conséquent, vous ne devriez pas avoir une chaîne de messages, par ex. a.getB (). getC (). doQuelque chose () . Suite à cette "loi" présente de nombreux autres avantages en plus de faciliter le débogage de NullPointerExceptions.

En général, je n'enchaîne pas les accesseurs comme celui-ci où il y a plus d'un getter nullable.

Si vous travaillez dans votre environnement, vous pouvez simplement définir un point d'arrêt et utiliser l'expression "évaluer l'expression". fonctionnalité de votre idée sur chaque élément successivement.

Mais vous allez vous gratter la tête au moment où vous recevrez ce message d'erreur des journaux de votre serveur de production. Il est donc préférable de conserver au maximum un élément nullable par ligne.

En attendant, nous pouvons rêver de l'opérateur de navigation sûr de groovy

Un échec précoce est également une option.

Partout dans votre code où une valeur NULL peut être renvoyée, envisagez d'introduire un contrôle pour une valeur de retour NULL.

public Foo getSomething()
{
  Foo result;
  ...
  if (result == null) {
    throw new IllegalStateException("Something is missing");
  }
  return result;
}

Voici comment trouver le bogue à l'aide d'Eclipse.

Tout d'abord, définissez un point d'arrêt sur la ligne:

someObject.getSomething().getSomethingElse().
getAnotherThing().getYetAnotherObject().getValue();

Exécuter le programme en mode débogage, autoriser le débogueur à basculer vers sa perspective lorsque la ligne est touchée.

Maintenant, mettez en surbrillance " someObject " et appuyez sur CTRL + MAJ + I (ou cliquez à droite et dites "inspecter").

Est-ce nul? Vous avez trouvé votre NPE. Est-ce non-nul? Ensuite, sélectionnez someObject.getSomething () (y compris la parenthèse) et inspectez-le. Est-ce nul? Etc. Continuez dans la chaîne pour déterminer où se trouve votre NPE, sans avoir à changer votre code.

Vous pouvez vous reporter à à propos de cette question d'éviter! = null .

Fondamentalement, si la valeur null est une réponse valide, vous devez la vérifier. Sinon, affirmez-le (si vous le pouvez). Mais quoi que vous fassiez, essayez de minimiser les cas où null est une réponse valide pour cette raison, entre autres.

Si vous devez arriver au point de scinder la ligne ou de procéder à un débogage complexe pour détecter le problème, c'est généralement le moyen utilisé par Dieu pour vous dire que votre code ne recherche pas assez tôt le code null. .

Si vous avez une méthode ou un constructeur qui prend un paramètre d'objet et que l'objet / la méthode en question ne peut raisonnablement pas traiter ce paramètre comme étant null, alors il suffit de vérifier et de lancer une exception NullPointerException à ce moment-là.

J'ai vu des gens inventer le "style de codage". règles pour contourner ce problème, telles que "vous n'êtes pas autorisé à utiliser plus d'un point sur une ligne". Mais cela encourage simplement une programmation qui repère le bogue au mauvais endroit.

Les expressions en chaîne telles que celle-ci sont difficiles à déboguer pour NullPointerExceptions (et la plupart des autres problèmes qui peuvent survenir). Je vous conseillerais donc de l’éviter. Vous avez probablement entendu parler de cela assez et, comme dans une précédente affiche, vous pouvez ajouter des points de rupture sur l’exception NullPointerException réelle pour voir où elle s’est produite.

Dans eclipse (et la plupart des IDE), vous pouvez également utiliser des expressions de contrôle pour évaluer le code exécuté dans le débogueur. Pour ce faire, vous devez sélectionner le code et utiliser le menu contextuel pour ajouter une nouvelle montre.

Si vous maîtrisez la méthode qui renvoie null, vous pouvez également considérer le modèle d'objet Null si null est une valeur valide à renvoyer.

Placez chaque getter sur sa propre ligne et procédez au débogage. Passez au-dessus (F6) de chaque méthode pour trouver quel appel renvoie null

Licencié sous: CC-BY-SA avec attribution
Non affilié à StackOverflow
scroll top