为什么 int num = Integer.getInteger("123") 会抛出 NullPointerException?

以下代码抛出NullPointerException:

int num = Integer.getInteger("123");

我的编译器是否在 null 上调用 getInteger,因为它是静态的?这没有任何意义!

Is my compiler invoking getInteger on null since it's static? That doesn't make any sense!

发生了什么事?

推荐答案

大局

这里有两个问题:

The Big Picture

There are two issues at play here:

  • Integer getInteger(String) 没有做你认为它做的事情
    • 在这种情况下返回 null
    • Integer getInteger(String) doesn't do what you think it does
      • It returns null in this case
      • 由于IntegernullNullPointerException被抛出

      要将 (String) "123" 解析为 (int) 123,您可以使用例如int Integer.parseInt(String).

      To parse (String) "123" to (int) 123, you can use e.g. int Integer.parseInt(String).

      • Java 语言指南/自动装箱
      • static int parseInt(String)
      • 静态整数 getInteger(String)

      以下是文档中关于此方法的作用的内容:

      Here's what the documentation have to say about what this method does:

      public static Integer getInteger(String nm):确定指定名称的系统属性的整数值.如果没有指定名称的属性,如果指定的名称为空或null,或者如果该属性没有正确的数字格式,则返回null.

      public static Integer getInteger(String nm): Determines the integer value of the system property with the specified name. If there is no property with the specified name, if the specified name is empty or null, or if the property does not have the correct numeric format, then null is returned.

      换句话说,该方法与将 String 解析为 int/Integer 值无关,而是与 System.getProperty 方法.

      In other words, this method has nothing to do with parsing a String to an int/Integer value, but rather, it has to do with System.getProperty method.

      诚然,这可能是一个相当大的惊喜.不幸的是,图书馆有这样的惊喜,但它确实教会了你一个宝贵的教训:总是查阅文档以确认方法的作用.

      Admittedly this can be quite a surprise. It's unfortunate that the library has surprises like this, but it does teach you a valuable lesson: always look up the documentation to confirm what a method does.

      巧合的是,这个问题的一个变体出现在 谜题归来:Schlock and Awe (TS-5186),Josh Bloch 和 Neal Gafter 的 2009 JavaOne 技术会议演示文稿.这是最后一张幻灯片:

      Coincindentally, a variation of this problem was featured in Return of the Puzzlers: Schlock and Awe (TS-5186), Josh Bloch and Neal Gafter's 2009 JavaOne Technical Session presentation. Here's the concluding slide:

      • 图书馆中潜伏着奇怪而可怕的方法
        • 有些名字听起来无伤大雅
        • 确保调用正确的方法
        • 阅读库文档
        • 不要违反最小惊讶原则
        • 不要违反抽象层次结构
        • 不要为截然不同的行为使用相似的名称

        为了完整起见,还有这些方法类似于Integer.getInteger:

        For completeness, there are also these methods that are analogous to Integer.getInteger:

        • Boolean.getBoolean(String)
        • Long.getLong(String)
        • 最令人震惊的对最小惊讶原则的违反
        • Java Base API 中最尴尬/误导性的方法?

        当然,另一个问题是 NullPointerException 是如何被抛出的.为了专注于这个问题,我们可以将代码片段简化如下:

        The other issue, of course, is how the NullPointerException gets thrown. To focus on this issue, we can simplify the snippet as follows:

        Integer someInteger = null;
        int num = someInteger; // throws NullPointerException!!!
        

        这里引用 Effective Java 2nd Edition,Item 49:Prefer primitive types to boxed primitives:

        Here's a quote from Effective Java 2nd Edition, Item 49: Prefer primitive types to boxed primitives:

        总而言之,只要您有选择,就优先使用原语而不是盒装原语.原始类型更简单、更快.如果您必须使用盒装图元,请小心!自动装箱减少了使用装箱原语的冗长,但不会降低危险.当您的程序使用 == 运算符比较两个装箱原语时,它会进行身份比较,这几乎肯定不是您想要的.当您的程序进行涉及装箱和未装箱原语的混合类型计算时,它会进行拆箱,而当您的程序进行拆箱时,它可能会抛出 NullPointerException.最后,当您的程序将原始值装箱时,可能会导致成本高昂且不必要的对象创建.

        In summary, use primitives in preference to boxed primitive whenever you have the choice. Primitive types are simpler and faster. If you must use boxed primitives, be careful! Autoboxing reduces the verbosity, but not the danger, of using boxed primitives. When your program compares two boxed primitives with the == operator, it does an identity comparison, which is almost certainly not what you want. When your program does mixed-type computations involving boxed and unboxed primitives, it does unboxing, and when your program does unboxing, it can throw NullPointerException. Finally, when your program boxes primitive values, it can result in costly and unnecessary object creations.

        有些地方你别无选择,只能使用盒装图元,例如泛型,否则您应该认真考虑使用盒装原语的决定是否合理.

        There are places where you have no choice but to use boxed primitives, e.g. generics, but otherwise you should seriously consider if a decision to use boxed primitives is justified.

        • 什么是Java/C# 中的 int 和 Integer 的区别?
        • 为什么 Java 中的自动装箱允许我有 3 个可能的布尔值?
        • 是否保证 new Integer(i) ==我在 Java 中?(是的!!!)
        • 在 Java 中比较两个整数时会自动执行拆箱发生?(不!!!)
        • Java noob:仅限对象的泛型?(是的,很遗憾)
        • What is the difference between an int and an Integer in Java/C#?
        • Why does autoboxing in Java allow me to have 3 possible values for a boolean?
        • Is it guaranteed that new Integer(i) == i in Java? (YES!!!)
        • When comparing two Integers in Java does auto-unboxing occur? (NO!!!)
        • Java noob: generics over objects only? (yes, unfortunately)

相关文章