Qu'est-ce qu'un NullPointerException, et comment puis-je le corriger?

que sont les exceptions Null Pointer ( java.lang.NullPointerException ) et quelles en sont les causes?

quelles méthodes / outils peuvent être utilisés pour déterminer la cause afin que vous arrêtiez l'exception de causer le programme de mettre fin prématurément?

210
demandé sur Ziggy 2008-10-20 17:18:09

12 réponses

quand vous déclarez une variable de référence (i.e. un objet) vous créez vraiment un pointeur vers un objet. Considérez le code suivant où vous déclarez une variable de type primitif int :

int x;
x = 10;

dans cet exemple, la variable x est une int et Java l'initialisera à 0 pour vous. Lorsque vous affectez à 10 dans la deuxième ligne de votre valeur 10 est écrit dans l'emplacement mémoire pointé par x.

mais, quand 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 (parce que le type est Integer qui est un type de référence). Comme vous n'avez pas encore dit ce qu'il faut pointer vers Java le met à nul, ce qui signifie Je ne pointe à rien ".

dans le deuxième ligne, le mot-clé new est utilisé pour instancier (ou créer) un objet de type entier et la variable pointeur num est assignée à cet objet. Vous pouvez maintenant référencer l'objet en utilisant l'opérateur dereferencing . (un point).

le Exception que vous avez demandé se produit lorsque vous déclarez une variable mais n'a pas créé un objet. Si vous essayez de dereference num avant de créer l'objet vous obtenez un NullPointerException . Dans la plupart des cas triviaux, le compilateur va attraper le problème et vous faire savoir que "num peut ne pas avoir été initialisé", mais parfois vous écrivez du code qui ne crée pas directement l'objet.

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'objet obj , en présumant plutôt qu'il a été créé avant que la méthode doSomething soit appelée. Malheureusement, il est possible d'appeler la méthode comme ceci:

doSomething(null);

, auquel cas obj est nul. Si la méthode est destinée à faire quelque chose à l'objet passé-dans, Il est approprié de jeter le NullPointerException parce que c'est une erreur de programmeur et le programmeur aura besoin de cette information à des fins de débogage.

il peut aussi y avoir des cas où le but de la méthode n'est pas seulement de fonctionner sur l'objet transmis, et par conséquent un paramètre nul peut être acceptable. Dans ce cas, vous devez vérifier pour un paramètre null et se comporter différemment. Vous devez également expliquer dans la documentation. Par exemple, doSomething pourrait s'écrire comme:

/**
  * @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 la trace de la pile

3287
répondu Vincent Ramdhanie 2018-05-12 04:34:24

NullPointerException s sont des exceptions qui se produisent lorsque vous essayez d'utiliser une référence qui pointe à aucun endroit dans la mémoire (null) comme s'il référençait un objet. Appeler une méthode sur une référence nulle ou essayer d'accéder à un champ d'une référence nulle déclenchera un NullPointerException . Ce sont les plus communs, mais d'autres moyens sont énumérés sur la NullPointerException javadoc page.

probablement le code d'exemple le plus rapide que j'ai pu trouver pour illustrer un NullPointerException serait:

public class Example {

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

}

sur la première ligne à l'intérieur de main , je mets explicitement Object référence obj égale à null . Cela signifie que j'ai une référence, mais elle ne montre aucun objet. Après cela, j'essaie de traiter la référence comme si elle pointe vers un objet en appelant une méthode sur elle. Il en résulte un NullPointerException parce qu'il n'y a pas de code à exécuter dans l'emplacement que la référence pointe.

(c'est un détail technique, mais je pense qu'il vaut la peine de le mentionner: une référence qui pointe vers nul n'est pas la même chose qu'un pointeur C qui pointe vers un emplacement mémoire invalide. Un pointeur nul ne pointe littéralement pas n'importe où , ce qui est subtilement différent de pointer vers un endroit qui se trouve être invalide.)

777
répondu Bill the Lizard 2017-12-25 14:24:54

Qu'est-ce qu'une NullPointerException?

Un bon endroit pour commencer est le Javadoc . Ils ont ceci couvert:

lancé lorsqu'une application tente d'utiliser null dans un cas où un l'objet est nécessaire. Il s'agit notamment de:

  • appelant la méthode d'instance d'un objet nul.
  • accès ou modification du champ d'un objet nul.
  • prenant la longueur de null comme s'il s'agissait d'un tableau.
  • accéder ou modifier les fentes de null comme si c'était un tableau.
  • lancer null comme si c'était une valeur Lancable.

les demandes doivent mentionner les instances de cette classe pour indiquer les autres l'usage illicite de l'objet nul.

il est également le cas que si vous tentez d'utiliser un null référence avec synchronized , qui lancera également cette exception, selon le JLS :

SynchronizedStatement:
    synchronized ( Expression ) Block
  • Sinon, si la valeur de L'Expression est nulle, un NullPointerException est lancé.

Comment puis-je le réparer?

donc vous avez un NullPointerException . Comment voulez-vous résoudre ce problème? Prenons un exemple simple qui jette un NullPointerException :

public class Printer {
    private String name;

    public void setName(String name) {
        this.name = name;
    }

    public void print() {
        printString(name);
    }

    private void printString(String s) {
        System.out.println(s + " (" + s.length() + ")");
    }

    public static void main(String[] args) {
        Printer printer = new Printer();
        printer.print();
    }
}

identifiez les valeurs nulles

la première étape consiste à identifier exactement les valeurs qui causent l'exception . Pour cela, nous avons besoin de faire un peu de débogage. Il est important d'apprendre à lire un stacktrace . Cela vous montrera où l'exception a été jetée:

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

ici, nous voyons que l'exception est jetée sur la ligne 13 (dans le printString ). Regardez la ligne et vérifiez quelles valeurs sont nulles par l'ajout de l'enregistrement des déclarations ou à l'aide d'un débogueur . Nous découvrons que s est nul, et appeler la méthode length sur elle jette l'exception. Nous pouvons voir que le programme cesse de lancer l'exception lorsque s.length() est supprimé de la méthode.

Trace où ces valeurs proviennent de

vérifiez ensuite d'où vient cette valeur. En suivant les appelants de la méthode, nous voyons que s est transmis avec printString(name) dans le print() , et this.name est null.

Trace où ces valeurs doivent être réglées

Où est fixé this.name ? Dans la méthode setName(String) . Avec un peu plus de débogage, nous pouvons voir que cette méthode n'est pas appelée à tous. Si la méthode a été appelée, assurez-vous de vérifier le ordre que ces méthodes sont appelées, et la méthode d'ensemble n'est pas appelé après la méthode d'impression.

cela suffit pour nous donner une solution: ajouter un appel à printer.setName() avant d'appeler printer.print() .

autres dispositifs fixes

la variable peut avoir une valeur par défaut (et setName peut empêcher qu'elle soit définie à null):

private String name = "";

soit la méthode print soit la méthode printString peut cochez la case "null , par exemple:

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

ou vous pouvez concevoir la classe de sorte que name a toujours une valeur non nulle :

public class Printer {
    private final String name;

    public Printer(String name) {
        this.name = Objects.requireNonNull(name);
    }

    public void print() {
        printString(name);
    }

    private void printString(String s) {
        System.out.println(s + " (" + s.length() + ")");
    }

    public static void main(String[] args) {
        Printer printer = new Printer("123");
        printer.print();
    }
}

Voir aussi:

Je ne trouve toujours pas le problème

Si vous avez essayé de déboguer le problème et n'ont toujours pas de solution, vous pouvez poster une question pour plus d'aide, mais assurez-vous d'inclure ce que vous avez essayé jusqu'à présent. À tout le moins, inclut la chaîne de caractères dans la question, et marque les numéros de ligne importants dans le code. Aussi, essayer de simplifier le code d'abord (voir SSCCE ).

627
répondu fgb 2017-12-29 13:53:51

Question: Qu'est-ce qui cause un NullPointerException (NPE)?

comme vous devez le savoir, les types Java sont divisés en types primitifs ( boolean , int , etc.) et 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 façon Java de dire "aucun objet".

A NullPointerException est lancé à l'exécution chaque fois que votre programme tente d'utiliser un null comme si c'était une vraie référence. Par exemple, si vous écrivez ceci:

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

l'énoncé étiqueté" ici "va tenter d'exécuter la méthode length() sur une référence null , et cela lancera un NullPointerException .

il y a plusieurs façons d'utiliser une valeur null qui donnera un résultat NullPointerException . En fait, les seules choses que vous peut faire avec un null sans la cause d'une NPE sont:

  • l'affecter à une variable de référence ou de lire à partir d'une variable de référence,
  • l'attribuer à un élément de tableau ou de lire à partir d'un élément de tableau (à condition que la matrice de référence lui-même est non-nulle!),
  • passer en tant que paramètre ou le retourner comme un résultat, ou
  • tester en utilisant les opérateurs == ou != , ou instanceof .

Question: Comment lire la NPE stacktrace?

supposons que je compile 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)
$

première observation: la compilation réussit! Le problème dans le programme n'est pas une erreur de compilation. C'est une erreur runtime . (Certains IDEs peuvent prévenir votre programme de toujours jeter une exception ... mais pas le compilateur standard javac .)

deuxième observation: quand je lance le programme, il affiche deux lignes de "charabia". faux!! ce n'est pas charabia. C'est un stacktrace ... et il fournit informations vitales qui vous aideront à traquer l'erreur dans votre code, si vous prenez le temps de lire attentivement.

Alors, regardons ce qu'il dit:

Exception in thread "main" java.lang.NullPointerException

La première ligne de la trace de la pile vous dit un certain nombre de choses:

  • il vous indique le nom du fil Java dans lequel l'exception a été jetée. Pour un programme simple avec un fil (comme celui-ci), il sera "principal". Passons sur ...
  • il vous indique le nom complet de l'exception qui a été lancée; i.e. java.lang.NullPointerException .
  • si l'exception a un message d'erreur associé, qui sera affiché après le nom de l'exception. NullPointerException est inhabituel à cet égard, parce qu'il a rarement une message d'erreur.

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

at Test.main(Test.java:4)

cela nous dit un certain nombre de choses:

  • "au Test.main "dit que nous étions dans la méthode main de la classe Test .
  • " Test.java: 4" donne le nom du fichier source de la classe, et il nous dit que la déclaration où cela s'est produit est dans la ligne 4 du fichier.

si vous comptez les lignes dans le fichier ci-dessus, la ligne 4 est celle que j'ai étiqueté avec le commentaire "ici".

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

en bref, la trace de la pile nous indiquera sans ambiguïté quelle déclaration de le programme a lancé le NPE.

1-pas tout à fait vrai. Il y a des choses qu'on appelle des exceptions imbriquées...

Question: Comment retrouver la cause de l'exception NPE dans mon code?

C'est la partie difficile. La réponse courte est d'appliquer l'inférence logique aux preuves fournies par la trace de la pile, le code source et la documentation pertinente de L'API.

Let's illustrer avec l'exemple simple (ci-dessus). Nous commençons par regarder la ligne que la trace de la pile nous a indiqué est où le NPE s'est produit:

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

comment ça peut lancer un NPE?

en fait, il n'y a qu'un seul moyen: il ne peut se produire que si foo a la valeur null . Nous essayons ensuite d'exécuter la méthode length() sur null et .... BANG!

mais (je vous entends dire) que faire si le NPE a été jeté dans l'appel de méthode length() ?

si c'était le cas, la trace de la pile serait différente. La première ligne" at "dirait que l'exception a été jetée dans une certaine ligne dans la classe java.lang.String , et la ligne 4 de Test.java serait la deuxième ligne" at".

alors d'où vient ce null ? Dans ce cas, il est évident, et il est évident que nous devons faire pour le réparer. (Attribuez une valeur non nulle à foo .)

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

public class Test {

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

    private static int test(String[] bar, int pos) {
        return bar[pos].length();
    }

    public static void main(String[] 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)
$ 

donc maintenant nous avons deux lignes" at". La première est pour cette ligne:

return args[pos].length();

et la seconde est pour cette ligne:

int length = test(foo, 1);

en regardant la première ligne, comment cela pourrait-il lancer un NPE? Il y a deux façons:

  • si la valeur de bar est null puis bar[pos] lancera un NPE.
  • si la valeur de bar[pos] est null alors appeler length() sur elle lancera un NPE.

ensuite, nous devons déterminer lequel de ces scénarios explique ce qui se passe réellement. Nous commencerons par explorer la première:

d'Où vient bar ? C'est un paramètre de la méthode test appel, et si nous regardons comment test a été appelé, nous pouvons voir qu'il provient de la variable statique foo . En outre, nous pouvons voir clairement que nous avons initialisé foo à une valeur non nulle. Cela suffit pour rejeter provisoirement cette explication. (En théorie, quelque chose d'autre pourrait changement foo à null ... mais ce n'est pas ce qui se passe 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, il est! Et c'est le problème. Quand nous initialisons comme ceci:

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

nous attribuons un String[] avec deux éléments qui sont initialisés à null . Après cela, nous n'avons pas changé le contenu de foo ... donc foo[1] sera toujours null .

448
répondu Stephen C 2018-03-19 14:05:30

C'est comme si vous essayez d'accéder à un objet qui est null . Prenons l'exemple suivant:

TypeA objA;

en ce moment vous avez juste déclaré cet objet mais pas initialisé ou instancié . Et chaque fois que vous essayez d'accéder à une propriété ou une méthode en elle, il lancera NullPointerException qui a du sens.

voir l'exemple ci-dessous:

String a = null;
System.out.println(a.toString()); // NullPointerException will be thrown
374
répondu Rakesh Burbure 2018-05-15 14:58:39

une exception de pointeur nul est lancée lorsqu'une application tente d'utiliser null dans un cas où un objet est requis. Il s'agit notamment de:

  1. appelant la méthode d'instance d'un objet null .
  2. accéder ou modifier le champ d'un objet null .
  3. prenant la longueur de null comme s'il s'agissait d'un tableau.
  4. accéder ou modifier les slots de null comme si ont été d'un tableau.
  5. lancer null comme si c'était une valeur Lancable.

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

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

322
répondu nathan1138 2017-12-20 21:40:50

a NULL pointeur est un qui pointe à nulle part. Lorsque vous déréférencement d'un pointeur p , dites-vous "donnez-moi les données à l'emplacement stocké en "p". Quand p est un pointeur nul, l'emplacement stocké dans p est nowhere , vous dites"donnez-moi les données à l'emplacement "nulle part". Évidemment, il ne peut pas faire ça, donc il lance un NULL pointer exception .

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

299
répondu MrZebra 2017-12-25 14:30:50

de nombreuses explications sont déjà présentes pour expliquer comment cela se produit et comment le corriger, mais vous devez également suivre meilleures pratiques pour éviter NullPointerException du tout.

voir aussi: Une bonne liste de meilleures pratiques

j'ajouterais, très important, faire un bon usage du modificateur final . utilisant le modificateur" final "chaque fois qu'applicable en Java

résumé:

  1. utilisez le modificateur final pour appliquer une bonne initialisation.
  2. éviter de renvoyer null dans les méthodes, par exemple en retournant les collections vides le cas échéant.
  3. utiliser les annotations @NotNull et @Nullable
  4. Fail fast et l'utilisation affirme pour éviter la propagation des objets nuls par le biais de l'ensemble de l'application quand ils ne devraient pas être NULL.
  5. utiliser égal avec un objet connu en premier: if("knownObject".equals(unknownObject)
  6. Préfèrent valueOf() sur toString().
  7. Utiliser la valeur null sûr StringUtils méthodes StringUtils.isEmpty(null) .
285
répondu L. G. 2017-12-25 14:31:46

Une exception de pointeur null est un indicateur que vous utilisez un objet sans l'initialiser.

par exemple, ci-dessous est une classe d'étudiant qui va l'utiliser 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 code correct indiqué 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 ");
        }
    }
}
283
répondu javid piprani 2017-12-20 21:44:41

en Java, tout est sous forme de classe.

si vous voulez utiliser n'importe quel objet alors vous avez deux phases:

  1. Déclarer
  2. initialisation

exemple:

  • déclaration: Object a;
  • initialisation: a=new Object();

de Même pour le tableau de concept

  • déclaration: Item i[]=new Item[5];
  • initialisation: i[0]=new Item();

si vous ne donnez pas la section d'initialisation, alors le NullpointerException apparaît.

275
répondu ashish bhatt 2018-06-22 00:34:42

In Java toutes les variables que vous déclarez sont en fait des" références " aux objets (ou primitives) et non aux objets eux-mêmes.

lorsque vous tentez d'exécuter une méthode objet, la référence demande à l'objet vivant d'exécuter cette méthode. Mais si la référence renvoie à NULL (nothing, zero, void, nada) alors il n'y a aucun moyen que la méthode soit exécutée. Alors le runtime vous le fait savoir en lançant une NullPointerException.

votre référence est" pointer "vers null, donc"Null -> pointeur".

l'objet vit dans l'espace mémoire VM et la seule façon d'y accéder est d'utiliser les références this . Prenez cet exemple:

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

et à un autre endroit dans 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...

c'est une chose importante à savoir - quand il n'y a plus de références à un objet (dans l'exemple ci-dessus quand reference et otherReference les deux pointent vers null) alors l'objet est"injoignable". Il n'y a aucun moyen que nous puissions travailler avec elle, donc cet objet est prêt à être collecté, et à un moment donné, la VM libérera la mémoire utilisée par cet objet et en affectera une autre.

265
répondu OscarRyz 2018-08-10 07:52:57

une autre occurrence d'un NullPointerException se produit lorsqu'on déclare un tableau d'objets, puis qu'on essaie immédiatement de déréférencer des éléments à l'intérieur de celui-ci.

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

cette NPE particulière peut être évitée si l'ordre de comparaison est inversé; à savoir, utiliser .equals sur un objet non nul garanti.

Tous les éléments à l'intérieur d'un tableau sont initialisés à leur valeur initiale ; pour toute type d'objet tableau, cela signifie que tous les éléments sont 151940920" .

Vous doit initialiser les éléments dans le tableau avant l'accès ou de déréférencement.

String[] phrases = new String[] {"The bird", "A bird", "My bird", "Bird"};
String keyPhrase = "Bird";
for(String phrase : phrases) {
    System.out.println(phrase.equals(keyPhrase));
}
252
répondu Makoto 2017-12-25 14:35:15