Why Does Int Num = Integer.Getinteger("123") Throw Nullpointerexception

Why does int num = Integer.getInteger(123) throw NullPointerException?

The Big Picture

There are two issues at play here:

  • Integer getInteger(String) doesn't do what you think it does

    • It returns null in this case
  • the assignment from Integer to int causes auto-unboxing

    • Since the Integer is null, NullPointerException is thrown

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

References

  • Java Language Guide/Autoboxing

Integer API references

  • static int parseInt(String)
  • static Integer getInteger(String)

On Integer.getInteger

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

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.

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.

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:

The Moral


  • Strange and terrible methods lurk in libraries

    • Some have innocuous sounding names
  • If your code misbehaves

    • Make sure you're calling the right methods
    • Read the library documentation
  • For API designers

    • Don't violate the principle of least astonishment
    • Don't violate the abstraction hierarchy
    • Don't use similar names for wildly different behaviors

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

  • Boolean.getBoolean(String)
  • Long.getLong(String)

Related questions

  • Most Astonishing Violation of the Principle of Least Astonishment
  • Most awkward/misleading method in Java Base API ?

On autounboxing

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!!!

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

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.

Related questions

  • 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)

Why comparing Integer with int can throw NullPointerException in Java?

The Short Answer

The key point is this:

  • == between two reference types is always reference comparison
    • More often than not, e.g. with Integer and String, you'd want to use equals instead
  • == between a reference type and a numeric primitive type is always numeric comparison
    • The reference type will be subjected to unboxing conversion
    • Unboxing null always throws NullPointerException
  • While Java has many special treatments for String, it is in fact NOT a primitive type

The above statements hold for any given valid Java code. With this understanding, there is no inconsistency whatsoever in the snippet you presented.



The Long Answer

Here are the relevant JLS sections:

JLS 15.21.3 Reference Equality Operators == and !=

If the operands of an equality operator are both of either reference type or the null type, then the operation is object equality.

This explains the following:

Integer i = null;
String str = null;

if (i == null) { // Nothing happens
}
if (str == null) { // Nothing happens
}
if (str == "0") { // Nothing happens
}

Both operands are reference types, and that's why the == is reference equality comparison.

This also explains the following:

System.out.println(new Integer(0) == new Integer(0)); // "false"
System.out.println("X" == "x".toUpperCase()); // "false"

For == to be numerical equality, at least one of the operand must be a numeric type:

JLS 15.21.1 Numerical Equality Operators == and !=

If the operands of an equality operator are both of numeric type, or one is of numeric type and the other is convertible to numeric type, binary numeric promotion is performed on the operands. If the promoted type of the operands is int or long, then an integer equality test is performed; if the promoted type is float or double`, then a floating-point equality test is performed.

Note that binary numeric promotion performs value set conversion and unboxing conversion.

This explains:

Integer i = null;

if (i == 0) { //NullPointerException
}

Here's an excerpt from Effective Java 2nd Edition, Item 49: Prefer primitives to boxed primitives:

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.

References

  • JLS 4.2. Primitive Types and Values
    • "The numeric types are the integral types and the floating-point types."
  • JLS 5.1.8 Unboxing Conversion
    • "A type is said to be convertible to a numeric type if it is a numeric type, or it is a reference type that may be converted to a numeric type by unboxing conversion."
    • "Unboxing conversion converts [...] from type Integer to type int"
    • "If r is null, unboxing conversion throws a NullPointerException"
  • Java Language Guide/Autoboxing
  • JLS 15.21.1 Numerical Equality Operators == and !=
  • JLS 15.21.3 Reference Equality Operators == and !=
  • JLS 5.6.2 Binary Numeric Promotion

Related questions

  • When comparing two Integers in Java does auto-unboxing occur?
  • Why are these == but not equals()?
  • Java: What’s the difference between autoboxing and casting?

Related questions

  • What is the difference between an int and an Integer in Java/C#?
  • Is it guaranteed that new Integer(i) == i in Java? (YES!!! The box is unboxed, not other way around!)
  • Why does int num = Integer.getInteger("123") throw NullPointerException? (!!!)
  • Java noob: generics over objects only? (yes, unfortunately)
  • Java String.equals versus ==

Use of Integer.getInteger()

The Integer.getInteger(String) method states the following:

The first argument is treated as the name of a system property. System properties are accessible through the System.getProperty(java.lang.String) method. The string value of this property is then interpreted as an integer value using the grammar supported by decode and an Integer object representing this value is returned.

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.

The other method, with two parameters, has a default value that is returned instead of null, if the parameter is not set or is an invalid integer.

Since sun.arch.data.model is a valid property with a numeric value, its value is returned both times (it is 32). com.samples.data.model is either non-existent or non-numeric and so the invalid handling logic is invoked instead, returning the default of 5 when specified, and null in the second call, where the default isn't specified.

How do I convert a String to an int in Java?

String myString = "1234";
int foo = Integer.parseInt(myString);

If you look at the Java documentation you'll notice the "catch" is that this function can throw a NumberFormatException, which you can handle:

int foo;
try {
foo = Integer.parseInt(myString);
}
catch (NumberFormatException e) {
foo = 0;
}

(This treatment defaults a malformed number to 0, but you can do something else if you like.)

Alternatively, you can use an Ints method from the Guava library, which in combination with Java 8's Optional, makes for a powerful and concise way to convert a string into an int:

import com.google.common.primitives.Ints;

int foo = Optional.ofNullable(myString)
.map(Ints::tryParse)
.orElse(0)

Integer.valueOf() vs. Integer.parseInt()

Actually, valueOf uses parseInt internally. The difference is parseInt returns an int primitive while valueOf returns an Integer object. Consider from the Integer.class source:

public static int parseInt(String s) throws NumberFormatException {
return parseInt(s, 10);
}

public static Integer valueOf(String s, int radix) throws NumberFormatException {
return Integer.valueOf(parseInt(s, radix));
}

public static Integer valueOf(String s) throws NumberFormatException {
return Integer.valueOf(parseInt(s, 10));
}

As for parsing with a comma, I'm not familiar with one. I would sanitize them.

int million = Integer.parseInt("1,000,000".replace(",", ""));

Why does Float.parseFloat() throw both NumberFormatException and NullPointerException but Integer.parseInt() only throws NumberFormatException?

It is definitely a historical artifact.

This inconsistency and related documentation issues have been raised as a Java Bug a few times over the years. For example:

  • https://bugs.openjdk.java.net/browse/JDK-6463998
  • https://bugs.openjdk.java.net/browse/JDK-7133642
  • https://bugs.openjdk.java.net/browse/JDK-4787924

In the earliest of these, the Sun engineers who were assigned to deal with the issue wrote this:

It is reasonable to expect the same exceptions to be thrown for null; however, these api's are very old and may not be able to be changed at this point.

Will consider for Tiger. [That was Java 5.0]

2002-12-03

Then a year later:

Since the exception behavior is long-standing and specified in the JavaDoc, it is impractical to change either method's behavior at this time. Closing as will not fix.

2003-10-21

Why does a source code analyzer claim a NullPointerException could be thrown despite a check for null

You're right. It seems the tool may be bugged as this is mentioned by the language specification:

The conditional-and operator && is like & (§15.22.2), but evaluates its right-hand operand only if the value of its left-hand operand is true.

Parse String to Integer throws NullpointerException

Integer.getInteger() is not the correct method to use.

You should be using Integer.valueOf()

Integer.getInteger(String s) will return the integer system property with the key s.

The null pointer occurs because this method can't find the property with the key you supply and returns null. Java then tries to unbox this to an int and null pointers.



Related Topics



Leave a reply



Submit