2010-09-28 48 views
4

考虑这个类:为什么这个地图检索产生一个NPE?

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

如果我用注释行替换现有的线紧贴它下面的工作:

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循环的第二次迭代期间上线Float foo =...生产如预期的那样,分配foo = null。为什么这两种情况下的行为不同?

+1

我会声明'final TestMap tm = ...'并放弃'tm == null'检查。 – 2010-09-28 16:12:10

回答

17

键“B”的值为空。但是由于你使用文字0F而不是Float(包装器),所以你的条件表达式的返回类型是float(原始),所以这个值必须被autounboxed(原语),然后自动复制(返回到一个对象) 。这导致了NPE。

比较,当你使用

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

作为一个附加的解释发生了什么,这里就是你的条件是做(出明确的拳):

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定义什么的返回类型有条件的操作符会。这非常复杂,我发现通过实验学习更容易:-)。

+0

这很棘手 - 没想到有条件地根据第一个条件修改第二个条款的返回类型......感谢解释。 – Greg 2010-09-28 16:07:16

+0

@Greg:是的,这部分起初可能会让人困惑。 Java需要静态地(在编译时)知道返回类型是什么,所以它需要选择适用于这两种可能性的单一返回类型。 – 2010-09-28 16:10:28

相关问题