J'ai ce code:
package tests;
import java.util.Hashtable;
public class Tests {
public static void main(String[] args) {
Hashtable<String, Boolean> modifiedItems = new Hashtable<String, Boolean>();
System.out.println("TEST 1");
System.out.println(modifiedItems.get("item1")); // Prints null
System.out.println("TEST 2");
System.out.println(modifiedItems.get("item1") == null); // Prints true
System.out.println("TEST 3");
System.out.println(Boolean.valueOf(null)); // Prints false
System.out.println("TEST 4");
System.out.println(Boolean.valueOf(modifiedItems.get("item1"))); // Produces NullPointerException
System.out.println("FINISHED!"); // Never executed
}
}
Mon problème est que je ne comprends pas pourquoi le test 3 fonctionne correctement (il imprime false
et ne produit pas NullPointerException
) pendant que le test 4 lance un fichier NullPointerException
. Comme vous pouvez le voir dans les tests 1 et 2 , null
et modifiedItems.get("item1")
sont égaux à et null
.
Le comportement est le même dans Java 7 et 8.
java
nullpointerexception
boolean
David E
la source
la source
null
à la même fonction ne génère pas de NPE! Il y a une bonne raison à cela, mais c'est certainement déroutant à première vue :-)==
on l'applique.Réponses:
Vous devez regarder attentivement quelle surcharge est invoquée:
Boolean.valueOf(null)
appelleBoolean.valueOf(String)
. Cela ne jette pas unNPE
même s'il est fourni avec un paramètre nul.Boolean.valueOf(modifiedItems.get("item1"))
appelleBoolean.valueOf(boolean)
, carmodifiedItems
les valeurs de sont de typeBoolean
, ce qui nécessite une conversion de déballage. DepuismodifiedItems.get("item1")
estnull
, il est le unboxing de cette valeur - pasBoolean.valueOf(...)
- ce qui jette le NPE.Les règles pour déterminer quelle surcharge est invoquée sont assez épineuses , mais elles vont à peu près comme ceci:
Dans un premier passage, une correspondance de méthode est recherchée sans autoriser le boxing / unboxing (ni les méthodes d'arité variable).
null
est une valeur acceptable pour aString
mais pasboolean
,Boolean.valueOf(null)
correspond àBoolean.valueOf(String)
dans cette passe;Boolean
est pas acceptable pour les deuxBoolean.valueOf(String)
ouBoolean.valueOf(boolean)
, si aucune méthode est adaptée dans ce col pourBoolean.valueOf(modifiedItems.get("item1"))
.Dans un second passage, une correspondance de méthode est recherchée, permettant le boxing / unboxing (mais toujours pas les méthodes d'arité variable).
Boolean
peut être déballéboolean
, doncBoolean.valueOf(boolean)
correspondBoolean.valueOf(modifiedItems.get("item1"))
à cette passe; mais une conversion de déballage doit être insérée par le compilateur pour l'invoquer:Boolean.valueOf(modifiedItems.get("item1").booleanValue())
(Il y a une troisième passe permettant les méthodes d'arité variable, mais ce n'est pas pertinent ici, car les deux premières passes correspondent à ces cas)
la source
Boolean.valueOf(modifiedItems.get("item1").booleanValue())
dans le code source au lieu deBoolean.valueOf(modifiedItems.get("item1"))
?.booleanValue()
enfoui dans l'expression. Deux observations: 1) l'auto (un) boxing est une fonctionnalité délibérée de Java pour supprimer les crampes syntaxiques; le faire vous-même est possible, mais pas idiomatique; 2) cela ne vous aide pas du tout - cela n'empêche certainement pas le problème de se produire, ni ne donne aucune information supplémentaire lorsque l'échec se produit (la trace de la pile serait identique, car le code exécuté est identique).Puisque
modifiedItems.get
renvoie aBoolean
(qui ne peut pas être converti en aString
), la signature qui serait utilisée estBoolean.valueOf(boolean)
, où leBoolean
est envoyé à une primitiveboolean
. Une foisnull
retourné là-bas, l'envoi échoue avec unNullPointerException
.la source
Signature de méthode
La méthode
Boolean.valueOf(...)
a deux signatures:public static Boolean valueOf(boolean b)
public static Boolean valueOf(String s)
Votre
modifiedItems
valeur estBoolean
. Vous ne pouvez pas lancerBoolean
versString
cas, la première signature sera donc choisieUnboxing booléen
Dans votre déclaration
qui peut être lu comme
Cependant,
modifiedItems.get("item1")
retournenull
donc vous aurez essentiellementce qui conduit évidemment à un
NullPointerException
la source
Comme Andy l'a déjà très bien décrit la raison de
NullPointerException
:ce qui est dû au déballage booléen:
se convertir en:
au moment de l'exécution, puis il jette
NullPointerException
simodifiedItems.get("item1")
est nul.Maintenant, je voudrais ajouter un point de plus ici que le déballage des classes suivantes à leurs primitives respectives peut également produire une
NullPointerException
exception si leurs objets retournés correspondants sont nuls.Voici le code:
la source
Une façon de le comprendre est que lorsque
Boolean.valueOf(null)
est invoqué, java est précisément dit d'évaluer null.Cependant, quand
Boolean.valueOf(modifiedItems.get("item1"))
est invoqué, java est invité à obtenir une valeur du HashTable de type d'objet Boolean, mais il ne trouve pas le type Boolean à la place, il trouve une impasse (null) même s'il attendait Boolean. L'exception NullPointerException est levée parce que les créateurs de cette partie de java ont décidé que cette situation est une instance de quelque chose dans le programme qui tourne mal et qui nécessite l'attention du programmeur. (Quelque chose d'inattendu s'est produit.)Dans ce cas, c'est plus la différence entre déclarer délibérément que vous vouliez que le null soit là, et java trouver une référence manquante à un objet (null) où un objet était destiné à être trouvé.
Pour plus d'informations sur NullPointerException, consultez cette réponse: https://stackoverflow.com/a/25721181/4425643
la source