为什么这段代码会抛出NullPointerException异常?

6
最终我得到了答案,但是它让我困惑了一段时间。
为什么运行以下代码会抛出NullPointerException?
import java.util.*;

class WhyNullPointerException {
    public static void main( String [] args ){
       // Create a map
        Map<String,Integer> m = new HashMap<String,Integer>();
        // Get the previous value, obviously null.
        Integer a = m.get( "oscar" );
        // If a is null put 1, else increase a
        int p = a == null ? 
            m.put( "oscar", 1) : 
            m.put( "oscar", a++ ); // Stacktrace reports Npe in this line
    }
}

请注意,如果一段时间后没有人回答问题,那么自己回答问题是完全可以接受的。 - Earlz
如果这是您的软件中的常见模式,您可以查看ApacheCommons DefaultedMap来装饰地图以自动返回1。http://commons.apache.org/collections/apidocs/org/apache/commons/collections/map/DefaultedMap.html - I82Much
@I82Much 感谢提供链接。实际上,我正在撰写有关Java 7中闭包的博客文章 :P 这是链接:(虽然是用西班牙语)http://bit.ly/ClosuresEnJavaMexico - OscarRyz
2个回答

11

因为 m.put 返回 null(表示没有“先前”值),而您正在尝试将其赋值给 int。将 int p 替换为 Integer p 即可解决。

这在 JLS 5.1.8 中有说明:

5.1.8 拆箱转换

在运行时,拆箱转换按以下方式进行:

  • 如果 rnull,则拆箱转换会抛出 NullPointerException

与问题无关,只是一个旁边的建议,考虑遵循 DRY 原则,可以这样写:

    Integer p = m.put("oscar", a == null ? 1 : a++);

这样更易读一些 :)


这与自动装箱有关吗? - Johannes Schaub - litb
@Johannes:确实如此。如果Integer为null,则自动将其拆箱为int - 拆箱引发异常。 - Anon.
1
@Johannes:确实,null 无法拆箱为基本类型,会抛出 NPE。请参阅自动装箱指南 - BalusC
1
实际上,堆栈跟踪是误导性的,因为它让你认为问题在 a++ 上,但是尝试用任何数字替换它,例如 put("oscar", /*a++*/ 4),那么 Npe 返回的行将是 put("oscar",1) 所在的位置。我不确定为什么会在那一行报告它。 - OscarRyz

5
你正在将m.put()的返回值赋值给int p。但是在这种情况下,put()返回null,你不能将int赋值给null
HashMap.put()的Javadoc中可以得知:

返回值: 与指定键关联的上一个值;如果没有key的映射,则返回null。


网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接