Qu’est-ce qu’une exception NullPointerException et comment la réparer?

Quelles sont les exceptions de pointeur nul ( java.lang.NullPointerException ) et quelles en sont les causes?

Quelles méthodes / outils pouvez-vous utiliser pour déterminer la cause afin d’empêcher l’exception de provoquer la fin prématurée du programme?

Related of "Qu’est-ce qu’une exception NullPointerException et comment la réparer?"

Lorsque vous déclarez une variable de référence (un object par exemple), vous créez réellement un pointeur sur un object. Considérons le code suivant où vous déclarez une variable de type primitif int :

 int x; x = 10; 

Dans cet exemple, la variable x est un int et Java l’initialisera à 0 pour vous. Lorsque vous l’affectez à 10 dans la deuxième ligne, votre valeur 10 est écrite dans l’emplacement de mémoire désigné par x.

Mais, lorsque vous essayez de déclarer un type de référence, quelque chose de différent se produit. Prenez le code suivant:

 Integer num; num = new Integer(10); 

La première ligne déclare une variable nommée num , mais elle ne contient pas de valeur primitive. Au lieu de cela, il contient un pointeur (car le type est Integer qui est un type de référence). Puisque vous n’avez pas encore dit ce que vous devez indiquer, Java le met à zéro, ce qui signifie ” Je ne pointe rien “.

Dans la deuxième ligne, le new mot-clé est utilisé pour instancier (ou créer) un object de type Integer et la variable pointeur est affectée à cet object. Vous pouvez maintenant référencer l’object à l’aide de l’opérateur de déréférencement . (un point).

L’ Exception laquelle vous avez posé la question se produit lorsque vous déclarez une variable sans créer d’object. Si vous tentez de déréférencer num AVANT de créer l’object, vous obtenez une NullPointerException . Dans les cas les plus sortingviaux, le compilateur détectera le problème et vous informera que “num n’a peut-être pas été initialisé” mais que vous écrivez parfois du code qui ne crée pas directement l’object.

Par exemple, vous pouvez avoir une méthode comme suit:

 public void doSomething(SomeObject obj) { //do something to obj } 

Dans ce cas, vous ne créez pas l’object obj , en supposant plutôt qu’il a été créé avant l’ doSomething méthode doSomething . Malheureusement, il est possible d’appeler la méthode comme ceci:

 doSomething(null); 

Dans ce cas, obj est nul. Si la méthode est destinée à faire quelque chose à l’object transmis, il convient de lancer l’ NullPointerException car c’est une erreur du programmeur et le programmeur aura besoin de cette information à des fins de débogage.

Alternativement, il peut y avoir des cas où le but de la méthode n’est pas uniquement d’opérer sur l’object passé, et donc un paramètre nul peut être acceptable. Dans ce cas, vous devrez rechercher un paramètre nul et vous comporter différemment. Vous devez également expliquer cela dans la documentation. Par exemple, doSomething peut être écrit comme doSomething :

 /** * @param obj An optional foo for ____. May be null, in which case * the result will be ____. */ public void doSomething(SomeObject obj) { if(obj != null) { //do something } else { //do something else } } 

Enfin, comment identifier l’exception et la cause en utilisant Stack Trace

NullPointerException s sont des exceptions qui se produisent lorsque vous essayez d’utiliser une référence qui ne pointe vers aucun emplacement de la mémoire (null) comme si elle faisait référence à un object. L’appel d’une méthode sur une référence null ou la tentative d’access à un champ de référence null déclenchera une NullPointerException . Celles-ci sont les plus courantes, mais d’autres méthodes sont répertoriées sur la page javadoc NullPointerException .

Le code exemple le plus rapide que je pourrais trouver pour illustrer une NullPointerException serait probablement:

 public class Example { public static void main(Ssortingng[] args) { Object obj = null; obj.hashCode(); } } 

Sur la première ligne de main , je définis explicitement la référence d’ Object obj égale à null . Cela signifie que j’ai une référence, mais elle ne pointe vers aucun object. Après cela, j’essaye de traiter la référence comme si elle pointe vers un object en appelant une méthode dessus. Cela se traduit par une NullPointerException car il n’y a pas de code à exécuter à l’emplacement indiqué par la référence.

(Il s’agit d’une question technique, mais je pense qu’il convient de le mentionner: une référence qui pointe vers null n’est pas la même chose qu’un pointeur C qui pointe vers un emplacement de mémoire invalide. Un pointeur nul ne pointe nulle part , ce qui est subtilement différent de pointant vers un endroit qui est invalide.)

Qu’est-ce qu’une exception NullPointerException?

Les JavaDocs sont un bon sharepoint départ. Ils ont ce couvert:

Émis lorsqu’une application tente d’utiliser null dans le cas où un object est requirejs. Ceux-ci inclus:

  • Appeler la méthode d’instance d’un object null.
  • Accéder ou modifier le champ d’un object nul.
  • Prendre la longueur de null comme s’il s’agissait d’un tableau.
  • Accéder ou modifier les slots de null comme s’il s’agissait d’un tableau.
  • Lancer null comme s’il s’agissait d’une valeur Throwable.

Les applications doivent lancer des instances de cette classe pour indiquer d’autres utilisations illégales de l’object null.

Il est également vrai que si vous essayez d’utiliser une référence null avec synchronized , cela jettera également cette exception, selon le JLS :

 SynchronizedStatement: synchronized ( Expression ) Block 
  • Sinon, si la valeur de l’expression est nulle, une NullPointerException est levée.

Comment je le répare?

Donc, vous avez une NullPointerException . Comment le réparer? Prenons un exemple simple qui lance une NullPointerException :

 public class Printer { private Ssortingng name; public void setName(Ssortingng name) { this.name = name; } public void print() { printSsortingng(name); } private void printSsortingng(Ssortingng s) { System.out.println(s + " (" + s.length() + ")"); } public static void main(Ssortingng[] args) { Printer printer = new Printer(); printer.print(); } } 

Identifier les valeurs nulles

La première étape consiste à identifier exactement les valeurs à l’origine de l’exception . Pour cela, nous devons faire du débogage. Il est important d’apprendre à lire une stacktrace . Cela vous montrera où l’exception a été levée:

 Exception in thread "main" java.lang.NullPointerException at Printer.printSsortingng(Printer.java:13) at Printer.print(Printer.java:9) at Printer.main(Printer.java:19) 

Ici, nous voyons que l’exception est levée sur la ligne 13 (dans la méthode printSsortingng ). Examinez la ligne et vérifiez quelles valeurs sont nulles en ajoutant des instructions de journalisation ou en utilisant un débogueur . Nous découvrons que s est null et l’appel de la méthode length renvoie l’exception. Nous pouvons voir que le programme arrête de lancer l’exception lorsque s.length() est supprimé de la méthode.

Trace d’où proviennent ces valeurs

Vérifiez ensuite d’où vient cette valeur. En suivant les appelants de la méthode, nous voyons que s est passé avec printSsortingng(name) dans la méthode print() et this.name est null.

Tracer où ces valeurs doivent être définies

Où est ce this.name set? Dans la setName(Ssortingng) . Avec un peu plus de débogage, nous pouvons voir que cette méthode n’est pas appelée du tout. Si la méthode a été appelée, assurez-vous de vérifier l’ ordre dans lequel ces méthodes sont appelées et la méthode set n’est pas appelée après la méthode d’impression.

Ceci est suffisant pour nous donner une solution: ajoutez un appel à printer.setName() avant d’appeler printer.print() .

Autres correctifs

La variable peut avoir une valeur par défaut (et setName peut l’empêcher d’être définie sur null):

 private Ssortingng name = ""; 

printSsortingng méthode print ou printSsortingng peut vérifier la valeur null , par exemple:

 printSsortingng((name == null) ? "" : name); 

Ou vous pouvez concevoir la classe pour que le name ait toujours une valeur non nulle :

 public class Printer { private final Ssortingng name; public Printer(Ssortingng name) { this.name = Objects.requireNonNull(name); } public void print() { printSsortingng(name); } private void printSsortingng(Ssortingng s) { System.out.println(s + " (" + s.length() + ")"); } public static void main(Ssortingng[] args) { Printer printer = new Printer("123"); printer.print(); } } 

Voir également:

  • Éviter les instructions «! = Null» en Java?

Je ne trouve toujours pas le problème

Si vous avez essayé de déboguer le problème et que vous n’avez toujours pas de solution, vous pouvez poster une question pour obtenir de l’aide, mais assurez-vous d’inclure ce que vous avez essayé jusqu’à présent. Au minimum, incluez la chaîne de caractères dans la question et marquez les numéros de ligne importants dans le code. Essayez également de simplifier le code en premier (voir SSCCE ).

Question: Qu’est-ce qui cause une NullPointerException (NPE)?

Comme vous le savez, les types Java sont divisés en types primitifs ( boolean , int , etc.) et en types de référence . Les types de référence en Java vous permettent d’utiliser la valeur spéciale null qui est la manière de dire “pas d’object” de Java.

Une NullPointerException est lancée à l’exécution chaque fois que votre programme tente d’utiliser un null comme s’il s’agissait d’une véritable référence. Par exemple, si vous écrivez ceci:

 public class Test { public static void main(Ssortingng[] args) { Ssortingng foo = null; int length = foo.length(); // HERE } } 

l’instruction intitulée “HERE” va tenter d’exécuter la méthode length() sur une référence null , et cela lancera une NullPointerException .

Il existe de nombreuses manières d’utiliser une valeur null qui entraînera une NullPointerException . En fait, les seules choses que vous pouvez faire avec un null sans provoquer de NPE sont:

  • l’affecter à une variable de référence ou le lire à partir d’une variable de référence,
  • l’affecter à un élément de tableau ou le lire à partir d’un élément de tableau (à condition que la référence de tableau soit non nulle!),
  • le passer en paramètre ou le renvoyer comme résultat, ou
  • testez-le en utilisant les opérateurs == ou != ou instanceof .

Question: Comment lire le stacktrace NPE?

Supposons que je comstack et exécute le programme ci-dessus:

 $ javac Test.java $ java Test Exception in thread "main" java.lang.NullPointerException at Test.main(Test.java:4) $ 

Premier constat: la compilation réussit! Le problème dans le programme n’est pas une erreur de compilation. C’est une erreur d’ exécution . (Certains IDE peuvent avertir que votre programme lancera toujours une exception … mais pas le compilateur javac standard.)

Deuxième observation: quand je lance le programme, il affiche deux lignes de “gobbledy-gook”. FAUX!! Ce n’est pas gobbledy-gook. C’est un stacktrace … et il fournit des informations vitales qui vous aideront à retrouver l’erreur dans votre code, si vous prenez le temps de le lire attentivement.

Alors regardons ce qu’il dit:

 Exception in thread "main" java.lang.NullPointerException 

La première ligne de la trace de stack vous indique plusieurs choses:

  • Il vous indique le nom du thread Java dans lequel l’exception a été lancée. Pour un programme simple avec un thread (comme celui-ci), il sera “principal”. Allons-nous en …
  • Il vous indique le nom complet de l’exception qui a été lancée; c’est à dire java.lang.NullPointerException .
  • Si l’exception comporte un message d’erreur associé, celui-ci sera affiché après le nom de l’exception. NullPointerException est inhabituel à cet égard, car il contient rarement un message d’erreur.

La deuxième ligne est la plus importante pour diagnostiquer un NPE.

 at Test.main(Test.java:4) 

Cela nous dit un certain nombre de choses:

  • “at Test.main” indique que nous étions dans la méthode main de la classe Test .
  • “Test.java:4” donne le nom de fichier source de la classe, ET il nous dit que l’instruction où cela s’est produit est à la ligne 4 du fichier.

Si vous comptez les lignes dans le fichier ci-dessus, la ligne 4 est celle que j’ai étiquetée avec le commentaire “HERE”.

Notez que dans un exemple plus compliqué, il y aura beaucoup de lignes dans la trace de la stack NPE. Mais vous pouvez être sûr que la deuxième ligne (la première ligne “at”) vous indiquera où le NPE a été lancé 1 .

En bref, la trace de la stack nous indiquera sans ambiguïté quelle instruction du programme a généré le NPE.

1 – Pas tout à fait vrai. Il y a des choses appelées exceptions nestedes …

Question: Comment rechercher la cause de l’exception NPE dans mon code?

C’est la partie difficile. La réponse courte consiste à appliquer des inférences logiques à la preuve fournie par la trace de la stack, le code source et la documentation de l’API pertinente.

Illustrons d’abord avec l’exemple simple (ci-dessus). Nous commençons par examiner la ligne que la trace de la stack nous a indiqué où se trouvait le NPE:

 int length = foo.length(); // HERE 

Comment peut-on lancer un NPE?

En fait, il n’ya qu’un seul moyen: cela ne peut se produire que si foo a la valeur null . Nous essayons alors d’exécuter la méthode length() sur null et …. BANG!

Mais (je vous entends dire) et si le NPE était lancé dans l’appel de la méthode length() ?

Eh bien, si cela se produisait, la trace de la stack serait différente. La première ligne “at” dirait que l’exception a été lancée dans une ligne dans la classe java.lang.Ssortingng et la ligne 4 de Test.java serait la deuxième ligne “at”.

Alors d’où vient cette null ? Dans ce cas, c’est évident, et il est évident que nous devons faire pour y remédier. (Atsortingbuez une valeur non nulle à foo .)

OK, essayons un exemple un peu plus compliqué. Cela nécessitera une déduction logique .

 public class Test { private static Ssortingng[] foo = new Ssortingng[2]; private static int test(Ssortingng[] bar, int pos) { return bar[pos].length(); } public static void main(Ssortingng[] args) { int length = test(foo, 1); } } $ javac Test.java $ java Test Exception in thread "main" java.lang.NullPointerException at Test.test(Test.java:6) at Test.main(Test.java:10) $ 

Nous avons donc maintenant deux lignes “à”. Le premier est pour cette ligne:

 return args[pos].length(); 

et le second est pour cette ligne:

 int length = test(foo, 1); 

En regardant la première ligne, comment cela pourrait-il jeter un NPE? Il y a deux manières:

  • Si la valeur de bar est null bar[pos] lancera un NPE.
  • Si la valeur de bar[pos] est null appel de length() lancera un NPE.

Ensuite, nous devons déterminer lequel de ces scénarios explique ce qui se passe réellement. Nous allons commencer par explorer le premier:

D’où vient le bar ? C’est un paramètre de l’appel de la méthode de test , et si nous regardons comment le test été appelé, nous pouvons voir qu’il provient de la variable statique foo . De plus, nous pouvons voir clairement que nous avons initialisé foo à une valeur non nulle. Cela suffit pour écarter provisoirement cette explication. (En théorie, quelque chose d’autre pourrait changer foo en null … mais cela ne se produit pas ici.)

Alors qu’en est-il de notre deuxième scénario? Eh bien, nous pouvons voir que pos est 1 , ce qui signifie que foo[1] doit être null . Est-ce possible?

En effet, ça l’est! Et voilà le problème. Lorsque nous initialisons comme ceci:

 private static Ssortingng[] foo = new Ssortingng[2]; 

nous allouons un Ssortingng[] avec deux éléments initialisés à null . Après cela, nous n’avons pas changé le contenu de foo … alors foo[1] sera toujours null .

C’est comme si vous essayiez d’accéder à un object qui est null . Prenons l’exemple ci-dessous:

 TypeA objA; 

À ce moment, vous venez de déclarer cet object, mais pas initialisé ou instancié . Et chaque fois que vous essayez d’accéder à une propriété ou à une méthode, elle lancera NullPointerException ce qui est logique.

Voir aussi l’exemple ci-dessous:

 Ssortingng a = null; System.out.println(a.toSsortingng()); // NullPointerException will be thrown 

Une exception de pointeur nul est levée lorsqu’une application tente d’utiliser null dans le cas où un object est requirejs. Ceux-ci inclus:

  1. Appeler la méthode d’instance d’un object null .
  2. Accéder ou modifier le champ d’un object null .
  3. Prendre la longueur de null comme s’il s’agissait d’un tableau.
  4. Accéder ou modifier les slots de null comme s’il s’agissait d’un tableau.
  5. Lancer null comme s’il s’agissait d’une valeur Throwable.

Les applications doivent lancer des instances de cette classe pour indiquer d’autres utilisations illégales de l’object null .

Référence: http://docs.oracle.com/javase/8/docs/api/java/lang/NullPointerException.html

Un pointeur NULL est celui qui ne pointe nulle part. Lorsque vous déréférencer un pointeur p , vous dites “donnez-moi les données à l’emplacement stocké dans” p “. Lorsque p est un pointeur nul, l’emplacement stocké dans p est nowhere , vous dites” donnez-moi les données à l’emplacement “Nulle part” “. De toute évidence, il ne peut pas le faire, il jette donc une NULL pointer exception .

En général, c’est parce que quelque chose n’a pas été initialisé correctement.

De nombreuses explications sont déjà présentes pour expliquer comment cela se produit et comment le résoudre, mais vous devez également suivre les meilleures pratiques pour éviter les NullPointerException .

Voir aussi: Une bonne liste de bonnes pratiques

J’appendais, très important, faire un bon usage du modificateur final . Utiliser le modificateur “final” chaque fois qu’il est applicable en Java

Résumé:

  1. Utilisez le final modificateur pour appliquer une bonne initialisation.
  2. Évitez de renvoyer null dans les méthodes, par exemple en retournant des collections vides le cas échéant.
  3. Utilisez les annotations @NotNull et @Nullable
  4. Échec rapide et utilisation d’assertions pour éviter la propagation d’objects nuls dans toute l’application lorsqu’ils ne devraient pas être nuls.
  5. Utilise d’abord un object connu: if("knownObject".equals(unknownObject)
  6. Préférez valueOf() sur toSsortingng ().
  7. Utilisez les méthodes SsortingngUtils.isEmpty(null) sans SsortingngUtils SsortingngUtils.isEmpty(null) .

Une exception de pointeur nul indique que vous utilisez un object sans l’initialiser.

Par exemple, vous trouverez ci-dessous une classe d’étudiants qui l’utilisera dans notre code.

 public class Student { private int id; public int getId() { return this.id; } public setId(int newId) { this.id = newId; } } 

Le code ci-dessous vous donne une exception de pointeur nul.

 public class School { Student obj_Student; public School() { try { obj_Student.getId(); } catch(Exception e) { System.out.println("Null Pointer "); } } } 

Parce que vous utilisez Obj_Student , mais vous avez oublié de l’initialiser comme dans le bon code ci-dessous:

 public class School { Student obj_Student; public School() { try { obj_Student = new Student(); obj_Student.setId(12); obj_Student.getId(); } catch(Exception e) { System.out.println("Null Pointer "); } } } 

En Java, tout est sous la forme d’une classe.

Si vous souhaitez utiliser un object, vous avez deux phases:

  1. Déclarer
  2. Initialisation

Exemple:

  • Déclaration: Object a;
  • Initialisation: a=new Object();

Même chose pour le concept de tableau

  • Déclaration: Item i[]=new Item[5];
  • Initialisation: i[0]=new Item();

Si vous ne donnez pas la section d’initialisation, l’ NullpointerException apparaît.

En Java, toutes les variables que vous déclarez sont en fait des “références” aux objects (ou aux primitives) et non aux objects eux-mêmes.

Lorsque vous essayez d’exécuter une méthode d’object, la référence demande à l’object vivant d’exécuter cette méthode. Mais si la référence fait référence à NULL (rien, zéro, vide, nada), alors il n’y a pas moyen d’exécuter la méthode. Ensuite, le runtime vous en informe en lançant une exception NullPointerException.

Votre référence est “pointant” sur null, donc “Null -> Pointeur”.

L’object réside dans l’espace mémoire de la machine virtuelle et le seul moyen d’y accéder consiste à utiliser this références. Prenons cet exemple:

 public class Some { private int id; public int getId(){ return this.id; } public setId( int newId ) { this.id = newId; } } 

Et sur un autre endroit de votre code:

 Some reference = new Some(); // Point to a new object of type Some() Some otherReference = null; // Initiallly this points to NULL reference.setId( 1 ); // Execute setId method, now private var id is 1 System.out.println( reference.getId() ); // Prints 1 to the console otherReference = reference // Now they both point to the only object. reference = null; // "reference" now point to null. // But "otherReference" still point to the "real" object so this print 1 too... System.out.println( otherReference.getId() ); // Guess what will happen System.out.println( reference.getId() ); // :S Throws NullPointerException because "reference" is pointing to NULL remember... 

Ceci est une chose importante à savoir – quand il n’y a plus de références à un object (dans l’exemple ci-dessus, lorsque reference et otherReference tous deux null), l’object est “inaccessible”. Il n’y a aucun moyen de travailler avec cet object, donc cet object est prêt à être nettoyé, et à un moment donné, la VM libère la mémoire utilisée par cet object et en alloue une autre.

Une autre occurrence d’une NullPointerException se produit lorsque l’on déclare un tableau d’objects, puis tente immédiatement de déréférencer des éléments à l’intérieur.

 Ssortingng[] phrases = new Ssortingng[10]; Ssortingng keyPhrase = "Bird"; for(Ssortingng phrase : phrases) { System.out.println(phrase.equals(keyPhrase)); } 

Ce NPE particulier peut être évité si l’ordre de comparaison est inversé; à savoir, utilisez .equals sur un object non nul garanti.

Tous les éléments à l’intérieur d’un tableau sont initialisés à leur valeur initiale commune ; pour tout type de tableau d’objects, cela signifie que tous les éléments sont null .

Vous devez initialiser les éléments du tableau avant de les accéder ou de les déréférencer.

 Ssortingng[] phrases = new Ssortingng[] {"The bird", "A bird", "My bird", "Bird"}; Ssortingng keyPhrase = "Bird"; for(Ssortingng phrase : phrases) { System.out.println(phrase.equals(keyPhrase)); }