Lorsque vous déclarez une variable de référence (c'est-à-dire un objet), vous créez vraiment un pointeur sur 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 un int
et Java l'initialisera 0
pour vous. Lorsque vous lui affectez la valeur de 10
sur la deuxième ligne, votre valeur de 10
est écrite dans l'emplacement 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 encore 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 sur quoi pointer, Java le définit null
, ce qui signifie « Je ne pointe vers rien ».
Dans la deuxième ligne, le new
mot-clé est utilisé pour instancier (ou créer) un objet de type Integer
et la variable pointeur num
est affectée à cet Integer
objet.
Cela NullPointerException
se produit lorsque vous déclarez une variable mais que vous n'avez pas créé d'objet et que vous l'assignez à la variable avant d'essayer d'utiliser le contenu de la variable (appelé déréférencement ). Vous pointez donc quelque chose qui n'existe pas réellement.
Le déréférencement se produit généralement lors de l'utilisation .
pour accéder à une méthode ou un champ, ou [
pour indexer un tableau.
Si vous essayez de déréférencer num
AVANT de créer l'objet, vous obtenez un NullPointerException
. Dans les cas les plus triviaux, le compilateur détectera le problème et vous fera savoir que " num may not have been initialized
," mais parfois vous pouvez écrire 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
, mais supposez plutôt qu'il a été créé avant l' doSomething()
appel de la méthode. Remarque, il est possible d'appeler la méthode comme ceci:
doSomething(null);
Dans ce cas, obj
est null
. Si la méthode est destinée à faire quelque chose à l'objet transmis, il convient de lancer le NullPointerException
car c'est une erreur de programmeur et le programmeur aura besoin de ces informations à des fins de débogage. Veuillez inclure le nom de la variable objet dans le message d'exception, comme
Objects.requireNonNull(a, "a");
Alternativement, il peut y avoir des cas où le but de la méthode n'est pas uniquement d'opérer sur l'objet transmis, et donc un paramètre nul peut être acceptable. Dans ce cas, vous devrez vérifier un paramètre nul et vous comporter différemment. Vous devez également expliquer cela dans la documentation. Par exemple, doSomething()
pourrait s'écrire:
/**
* @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 localiser l'exception et la cause en utilisant Stack Trace
Quelles méthodes / outils peuvent être utilisés pour déterminer la cause afin que vous empêchiez l'exception de provoquer l'arrêt prématuré du programme?
Sonar avec findbugs peut détecter NPE.
Le sonar peut-il intercepter dynamiquement les exceptions de pointeur nul causées par JVM
int a=b
peut lancer un NPE si b est unInteger
. Il y a des cas où cela prête à confusion pour déboguer.NullPointerException
problèmes dans votre code est d'utiliser@Nullable
et d'@NotNull
annoter. La réponse suivante contient plus d'informations à ce sujet. Bien que cette réponse concerne spécifiquement l'IDE IntelliJ, elle est également applicable à d'autres outils comme l'est apparanet des commentaires. (BTW je ne suis pas autorisé à modifier cette réponse directement, peut-être que l'auteur peut l'ajouter?)NullPointerException
s sont des exceptions qui se produisent lorsque vous essayez d'utiliser une référence qui ne pointe vers aucun emplacement en mémoire (null) comme si elle faisait référence à 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 aNullPointerException
. Ce sont les plus courants, mais d'autres moyens sont répertoriés sur laNullPointerException
page javadoc.L'exemple de code le plus rapide que je pourrais illustrer
NullPointerException
serait probablement:Sur la première ligne à l'intérieur
main
, je définis explicitement laObject
référenceobj
égale ànull
. Cela signifie que j'ai une référence, mais qu'elle ne pointe vers 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 dessus. Il en résulte unNullPointerException
car il n'y a pas de code à exécuter à l'emplacement vers lequel pointe la référence.(Ceci est une technicité, mais je pense qu'il convient de 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 non valide. Un pointeur nul ne pointe littéralement nulle part , ce qui est subtilement différent de pointant vers un emplacement qui n'est pas valide.)
la source
null
qu'avant de l'utiliser, comme ceci . Avec les variables locales, le compilateur intercepterait cette erreur, mais dans ce cas, ce n'est pas le cas. Peut-être que cela apporterait un complément utile à votre réponse?Qu'est-ce qu'une NullPointerException?
Un bon point de départ est les JavaDocs . Ils ont ceci couvert:
Il est également possible que si vous essayez d'utiliser une référence nulle avec
synchronized
, cela lèvera également cette exception, par le JLS :Comment je le répare?
Vous avez donc un
NullPointerException
. Comment le corrigez-vous? Prenons un exemple simple qui lance unNullPointerException
:Identifier les valeurs nulles
La première étape consiste à identifier exactement les valeurs qui provoquent l'exception . Pour cela, nous devons effectuer un débogage. Il est important d'apprendre à lire une trace de pile . Cela vous montrera où l'exception a été levée:
Ici, nous voyons que l'exception est levée sur la ligne 13 (dans la
printString
méthode). Regardez la ligne et vérifiez quelles valeurs sont nulles en ajoutant des instructions de journalisation ou en utilisant un débogueur . Nous découvrons ques
c'est nul, et appeler lalength
méthode dessus lève l'exception. Nous pouvons voir que le programme cesse de lever l'exception lorsqu'ils.length()
est supprimé de la méthode.Tracer l'origine de ces valeurs
Vérifiez ensuite d'où vient cette valeur. En suivant les appelants de la méthode, nous voyons que cela
s
est passé avecprintString(name)
dans laprint()
méthode etthis.name
est nul.Trace où ces valeurs doivent être définies
Où est
this.name
placé? Dans lasetName(String)
méthode. 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, vérifiez 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.Cela suffit pour nous donner une solution: ajoutez un appel à
printer.setName()
avant d'appelerprinter.print()
.Autres correctifs
La variable peut avoir une valeur par défaut (et
setName
peut empêcher qu'elle soit définie sur null):La méthode
print
ouprintString
peut vérifier la valeur null , par exemple:Ou vous pouvez concevoir la classe de sorte qu'elle
name
ait toujours une valeur non nulle :Voir également:
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 publier une question pour obtenir de l'aide, mais assurez-vous d'inclure ce que vous avez essayé jusqu'à présent. Au minimum, incluez le stacktrace dans la question et marquez les numéros de ligne importants dans le code. Essayez également de simplifier le code en premier (voir SSCCE ).
la source
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 les types de référence . Les types de référence en Java vous permettent d'utiliser la valeur spécialenull
qui est la façon Java de dire "pas d'objet".A
NullPointerException
est lancé lors de l'exécution à chaque fois que votre programme tente d'utiliser unnull
comme s'il s'agissait d'une véritable référence. Par exemple, si vous écrivez ceci:l'instruction intitulée "ICI" va tenter d'exécuter la
length()
méthode sur unenull
référence, ce qui lancera aNullPointerException
.Il existe de nombreuses façons d'utiliser une
null
valeur qui entraînera unNullPointerException
. En fait, les seules choses que vous pouvez faire avec unnull
sans provoquer un NPE sont:==
ou!=
opérateurs, ouinstanceof
.Question: Comment lire la trace de pile NPE?
Supposons que je compile et exécute le programme ci-dessus:
Premier constat: la compilation réussit! Le problème dans le programme n'est PAS une erreur de compilation. Il s'agit d'une erreur d' exécution . (Certains IDE peuvent avertir que votre programme lèvera toujours une exception ... mais pas le
javac
compilateur standard .)Deuxième constat: lorsque je lance le programme, il sort deux lignes de "gobbledy-gook". FAUX!! Ce n'est pas gobbledy-gook. Il s'agit d'une trace de pile ... et elle fournit des informations vitales qui vous aideront à retrouver l'erreur dans votre code si vous prenez le temps de la lire attentivement.
Voyons donc ce qu'il dit:
La première ligne de la trace de pile vous indique un certain nombre de choses:
java.lang.NullPointerException
.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.
Cela nous indique un certain nombre de choses:
main
méthode de laTest
classe.Si vous comptez les lignes dans le fichier ci-dessus, la ligne 4 est celle que j'ai étiquetée avec le commentaire "ICI".
Notez que dans un exemple plus compliqué, il y aura beaucoup de lignes dans la trace de 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 dira sans ambiguïté quelle instruction du programme a jeté le NPE.
1 - Pas tout à fait vrai. Il y a des choses appelées exceptions imbriquées ...
Question: Comment puis-je rechercher la cause de l'exception NPE dans mon code?
C'est la partie difficile. La réponse courte consiste à appliquer une inférence logique aux preuves fournies par la trace de pile, le code source et la documentation API appropriée.
Illustrons d'abord l'exemple simple (ci-dessus). Nous commençons par regarder la ligne que la trace de pile nous a indiqué est l'endroit où le NPE s'est produit:
Comment cela peut-il lancer un NPE?
En fait, il n'y a qu'une seule façon: cela ne peut arriver que si
foo
a la valeurnull
. Nous essayons ensuite d'exécuter lalength()
méthodenull
et ... BANG!Mais (je vous entends dire) et si le NPE était jeté à l'intérieur de l'
length()
appel de méthode?Eh bien, si cela se produisait, la trace de la pile serait différente. La première ligne "at" dirait que l'exception a été levée dans une ligne de la
java.lang.String
classe et la ligne 4 deTest.java
serait la deuxième ligne "at".D'où cela
null
vient-il? Dans ce cas, c'est évident, et il est évident ce que nous devons faire pour y remédier. (Attribuez une valeur non nulle àfoo
.)OK, essayons donc un exemple un peu plus délicat. Cela nécessitera une déduction logique .
Nous avons donc maintenant deux lignes "at". Le premier est pour cette ligne:
et le second est pour cette ligne:
En regardant la première ligne, comment cela pourrait-il lancer un NPE? Il y a deux façons:
bar
estnull
alorsbar[pos]
lancera un NPE.bar[pos]
estnull
alors appeléelength()
, 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 le premier:
D'où
bar
vient-il? Il s'agit d'un paramètre de l'test
appel de méthode, et si nous regardons comment il atest
été appelé, nous pouvons voir qu'il provient de lafoo
variable statique. 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 changerfoo
ennull
... mais cela ne se produit pas ici.)Et notre deuxième scénario? Eh bien, nous pouvons voir que
pos
c'est le cas1
, ce qui signifie que celafoo[1]
doit êtrenull
. Est-ce possible?En effet, ça l'est! Et voilà le problème. Lorsque nous initialisons comme ceci:
nous allouons un
String[]
avec deux éléments qui sont initialisés ànull
. Après cela, nous n'avons pas changé le contenu defoo
... cefoo[1]
sera toujours le casnull
.la source
C'est comme si vous essayez d'accéder à un objet qui l'est
null
. Considérez l'exemple ci-dessous:Pour l'instant, vous venez de déclarer cet objet mais pas initialisé ni instancié . Et chaque fois que vous essayez d'accéder à une propriété ou une méthode, elle lance
NullPointerException
ce qui a du sens.Voir également cet exemple ci-dessous:
la source
Une exception de pointeur null est levée lorsqu'une application tente d'utiliser null dans le cas où un objet est requis. Ceux-ci inclus:
null
objet.null
objet.null
comme s'il s'agissait d'un tableau.null
comme s'il s'agissait d'une baie.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'
null
objet.Référence: http://docs.oracle.com/javase/8/docs/api/java/lang/NullPointerException.html
la source
null
comme cible d'unsynchronized
bloc, 2) en utilisant unnull
comme cible d'unswitch
, et unboxingnull
.Un
null
pointeur est celui qui ne pointe nulle part. Lorsque vous déréférencer un pointeurp
, vous dites "donnez-moi les données à l'emplacement stocké dans" p ". Quandp
est unnull
pointeur, l'emplacement stocké dansp
estnowhere
, vous dites" donnez-moi les données à l'emplacement "nulle part" ". De toute évidence, il ne peut pas faire cela, il lance donc anull pointer exception
.En général, c'est parce que quelque chose n'a pas été correctement initialisé.
la source
NULL
s'écrit commenull
en java. Et c'est une chose sensible à la casse.De nombreuses explications sont déjà présentes pour expliquer comment cela se produit et comment y remédier, mais vous devez également suivre les meilleures pratiques pour éviter
NullPointerException
tout.Voir aussi: Une bonne liste de bonnes pratiques
J'ajouterais, très important, de bien utiliser le
final
modificateur. Utilisation du modificateur "final" chaque fois qu'il est applicable en JavaRésumé:
final
modificateur pour appliquer une bonne initialisation.@NotNull
et@Nullable
if("knownObject".equals(unknownObject)
valueOf()
plustoString()
.StringUtils
méthodes sûres nullesStringUtils.isEmpty(null)
.la source
@Nullable
comme indiqué ci-dessus) et mettent en garde contre les erreurs potentielles. Il est également possible d'inférer et de générer de telles annotations (par exemple, IntelliJ peut le faire) sur la base de la structure de code existante.if (obj==null)
. S'il est nul, vous devez également écrire du code pour gérer cela également.En Java, tout (à l'exception des types primitifs) se présente sous la forme d'une classe.
Si vous souhaitez utiliser n'importe quel objet, vous avez deux phases:
Exemple:
Object object;
object = new Object();
Idem pour le concept de baie:
Item item[] = new Item[5];
item[0] = new Item();
Si vous ne donnez pas la section d'initialisation, le
NullPointerException
problème survient.la source
Une exception de pointeur nul est un indicateur que vous utilisez un objet sans l'initialiser.
Par exemple, ci-dessous se trouve une classe d'étudiants qui l'utilisera dans notre code.
Le code ci-dessous vous donne une exception de pointeur nul.
Parce que vous utilisez
student
, mais vous avez oublié de l'initialiser comme dans le bon code ci-dessous:la source
En 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 essayez d'exécuter une méthode d'objet, la référence demande à l'objet vivant d'exécuter cette méthode. Mais si la référence fait référence à NULL (rien, zéro, vide, nada), il n'y a aucun moyen d'exécuter la méthode. Ensuite, le runtime vous le fait savoir en lançant une NullPointerException.
Votre référence "pointe" vers null, donc "Null -> Pointer".
L'objet vit dans l'espace mémoire de la machine virtuelle et le seul moyen d'y accéder est d'utiliser des
this
références. Prenez cet exemple:Et à un autre endroit de votre code:
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 lesotherReference
deux pointent vers null) alors l'objet est "inaccessible". Il n'y a aucun moyen de travailler avec lui, donc cet objet est prêt à être récupéré, et à un moment donné, la machine virtuelle libérera la mémoire utilisée par cet objet et en allouera une autre.la source
Une autre occurrence de a
NullPointerException
se produit lorsque l'on déclare un tableau d'objets, puis essaie immédiatement de déréférencer des éléments à l'intérieur de celui-ci.Ce NPE particulier peut être évité 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 commune ; pour tout type de tableau d'objets, cela signifie que tous les éléments le sont
null
.Vous devez initialiser les éléments du tableau avant d'y accéder ou de les déréférencer.
la source
Optional
devait retourner null. Le mot-clé est très bien. Savoir se prémunir contre cela est essentiel. Cela en offre une occurrence courante et des moyens de l'atténuer.