I ran across a very weird NPE this morning, and reduced it to a simple example. Is this a JVM bug or correct behavior?
public class Test1 {
class Item {
Integer id = null;
public Integer getId() {return id;}
}
public Integer f() {
Item item = new Item();
// this works:
//return item == null ? new Integer(1) : item.getId();
// NPE??
return item == null ? 1 : item.getId();
}
public static void main(String[] args) {
Test1 t = new Test1();
System.out.println("id is: " + String.valueOf(t.f()));
}
}
Output from compile and run:
$ javac Test1.java
$ java Test1
Exception in thread "main" java.lang.NullPointerException
at Test1.f(Test1.java:12)
at Test1.main(Test1.java:16)
$
You can't throw an exception in a ternary clause. Both options must return a value, which throw new Exception(); doesn't satisfy.
Java ternary operator is the only conditional operator that takes three operands. It's a one-liner replacement for the if-then-else statement and is used a lot in Java programming. We can use the ternary operator in place of if-else conditions or even switch conditions using nested ternary operators.
Ternary Operator in Java A ternary operator evaluates the test condition and executes a block of code based on the result of the condition. if condition is true , expression1 is executed. And, if condition is false , expression2 is executed.
The type of the expression item == null ? 1 : item.getId()
is int
not Integer
. Therefore, Java needs to auto-unbox your Integer
to an int
(causing the NullPointerException
). Then it auto-boxes the result back to an Integer
(well it would if not for the NullPointerException
) to return from the method.
On the other hand, the expression item == null ? new Integer(1) : item.getId()
has a type of Integer
and no auto-unboxing needs to be done.
When you auto-unbox a null
Integer
, you get a NullPointerException
(see Autoboxing) and that is what you are experiencing.
To answer your question, this is correct behavior.
If you decompile the class file you will see clearly your NPE...
return Integer.valueOf(item != null ? item.getId().intValue() : 1);
item
may not be null
, but when you call getId()
, that is returning null
. When you try to auto-unbox null
, you get an NPE.
The return type below is Integer
-
public Integer f() {
Item item = new Item();
// this works:
//return item == null ? new Integer(1) : item.getId();
// NPE??
return item == null ? 1 : item.getId();
}
And the result of the following -
item == null ? 1 : item.getId()
is null
in your case.
So, JVM is throwing NPE because it is trying to autobox null
.
Try -
new Integer(null); // and
Integer.valueOf(null);
both will throw NPE.
It happens because you are using conditional operator ?
. Line
return item == null ? 1 : item.getId();
is equivalent to
int result = item == null ? 1 : item.getId();
return result;
The result is int because of the first operand in your expression. This is the reason that your code works when you explicitly wrap 1 with Integer. In this case the compiler creates something like
Integer result = item == null ? new Integer(1) : item.getId();
return result;
So, NPE happens when attempting to "cast" item.getId() (that is null) to int.
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With