2010-09-28 7 views
4

Considérez cette classe:Pourquoi cette récupération de carte produit-elle un NPE?

public class TestMap extends HashMap<String, Float> { 

    public static void main(String[] args) { 
     TestMap tm = new TestMap(); 
     tm.put("A", 0F); 
     tm.put("B", null); 

     String[] keys = new String[]{"A", "B"}; 

     for (String key : keys) { 
      System.out.println(key); 
      Float foo = (tm == null ? 0F : tm.get(key)); 
//   Float foo = tm.get(key); 
      System.out.println(foo); 
     }  
    } 
} 

NullPointerException est produit sur la ligne Float foo =... au cours de la seconde itération de la boucle:

A 
0.0 
B 
Exception in thread "main" java.lang.NullPointerException 
    at TestMap.main(TestMap.java:14) 

Si je remplace la ligne existante avec la ligne commentée immédiatement au-dessous fonctionne comme prévu, assigner foo = null. Pourquoi le comportement est-il différent dans ces deux cas?

+1

Je déclarerais 'final TestMap tm = ...' et renoncer à la vérification 'tm == null'. –

Répondre

17

La valeur de la clé "B" est nulle. Mais le type de retour de votre expression conditionnelle est un float (primitif) dû à vous en utilisant le littéral 0F, pas un Float (wrapper), donc la valeur doit être autounboxed (à une primitive) puis autoboxed (retour à un objet) . Cela entraîne le NPE.

Comparer à ce qui se passe lorsque vous utilisez

Float foo = (tm == null ? Float.valueOf(0f) : tm.get(key)); 

Comme une explication supplémentaire, voici ce que votre condition est en train de faire (montrer la boxe explicite):

Float foo; 
float conditionalResult; 

if (tm == null) { 
    conditionalResult = 0F; 
} else { 
    conditionalResult = tm.get(key).floatValue(); //this throws the NPE 
} 
foo = Float.valueOf(conditionalResult); 

JLS 15.25 définit ce que le type de retour d'un opérateur conditionnel sera. C'est assez complexe, et je trouve qu'il est plus facile d'apprendre par l'expérimentation :-).

+0

C'est difficile - ne s'attendait pas à ce que le conditionnel modifie le type de retour de la deuxième clause basé sur le premier ... merci pour l'explication. – Greg

+0

@Greg: Oui, cette partie peut être déroutante au premier abord. Java doit savoir de façon statique (au moment de la compilation) quel est le type de retour, donc il doit choisir un type de retour unique qui fonctionne pour les deux possibilités. –