Numeric Type Promotion with Conditional Expression - java

I was toying around with java, and I noticed something. It can be best shown here:
boolean boo = true;
Object object1 = boo ? new Integer(1) : new Double(2.0);
Object object2;
if (boo)
object2 = new Integer(1);
else
object2 = new Double(2.0);
System.out.println(object1);
System.out.println(object2);
I would expect the two to be the same, but this is what gets printed:
1.0
1
Does anyone have a good explanation for this?

A ternary must return the same type for both conditions, so your first result (Integer) is promoted to a double to match 2.0. See also,
Object object1 = boo ? new Integer(1) : new Double(2.0);
System.out.println(object1.getClass().getName());
This is documented at JLS-15.25.2 - Numeric Conditional Expressions which reads (in part)
Otherwise, binary numeric promotion (§5.6.2) is applied to the operand types, and the type of the conditional expression is the promoted type of the second and third operands.
Note that binary numeric promotion performs value set conversion (§5.1.13) and may perform unboxing conversion (§5.1.8).

JLS section 15.25 has a table that summarizes the type of the conditional expression based on the type of its operands. For the case of Integer and Double, the table says that the type will be the result of applying binary numeric promotion to the arguments (§15.25.2)
Otherwise, binary numeric promotion (§5.6.2) is applied to the operand types, and the type of the conditional expression is the promoted type of the second and third operands.
Note that binary numeric promotion performs value set conversion (§5.1.13) and may perform unboxing conversion (§5.1.8).
Quoting binary numeric promotion:
If any operand is of a reference type, it is subjected to unboxing conversion (§5.1.8).
...
If either operand is of type double, the other is converted to double.
This is what's happening for
Object object1 = boo ? new Integer(1) : new Double(2.0);
The reference type new Integer(1) is unboxed to the primitive int 1.
The reference type new Double(2.0) is unboxed to the primitive double 2.0.
Binary numeric promotion is performed and the result is of type double. In this case, since boo is true, the primitive int 1 will be promoted to double as 1.0.
Since you are storing the result in an Object, the primitive result is boxed into its wrapper type.
For the case of
Object object2;
if (boo)
object2 = new Integer(1);
else
object2 = new Double(2.0);
the if/else construct does not perform numeric promotion. In fact there won't be any boxing conversion. Since boo is true, the if part will be executed and object2 will have the value new Integer(1).

Related

In Java, does "==" Box or Unbox when comparing an object and a constant value? [duplicate]

This question already has answers here:
When using == for a primitive and a boxed value, is autoboxing done, or is unboxing done
(3 answers)
Is it guaranteed that new Integer(i) == i in Java?
(2 answers)
Closed 2 years ago.
When comparing an Integer object and a constant value, does Java box the value or unbox the Integer object?
Based on what I have read, "==" is a reference comparison, therefore it's only logical to assume that Java boxes the constant to perform the reference comparison between the objects. Yet, the below test code seems to be give contradictory results.
Integer v1 = 1000;
Integer v2 = 1000;
boolean b1 = v1 == 1000; //True.
boolean b2 = v1 == v2; //False. Proof that 1000 boxes to new object and is not fetched from cache.
So how does object vs constant value comparison using == works in Java? Does the operator compare by value in this case?
What you call "a constant value" is an int literal, so its type is int.
JLS 15.21.1 says:
If the operands of an equality operator are both of numeric type, or one is of numeric type and the other is convertible (§5.1.8) to numeric type, binary numeric promotion is performed on the operands.
In your v1 == 1000 test, 1000 is of numeric type and v1 is convertible to numeric type, so binary numeric promotion is performed.
JLS 5.6.2 (Binary numeric promotion) says:
If any operand is of a reference type, it is subjected to unboxing conversion
Hence, the Integer operand - v1 - is unboxed to an int and a comparison of two ints is performed. Therefore the result of the comparison is true.
When you compare two reference types - v1 == v2 - no unboxing takes places, only the references are compared, as written in JLS 15.21.3:
If the operands of an equality operator are both of either reference type or the null type, then the operation is object equality.
Since 1000 is too large to be cached by the Integer cache, b1 and b2 are not referencing the same instance, and therefore the result of the comparison is false.
Integer pools are same to string pool but it caches value if integer objects in the range -128 to 127
So when you try to assign a value in this range to a wrapper object, the boxing operation will invoke Integer.valueOf method and in turn it will assign a reference to the object already in the pool.
but, if you assign a value outside this range to a wrapper reference type, Integer.valueOf will create a new Integer object for that value. And hence, comparing the reference for Integer objects having value outside this range will give you false
So in your case
Integer v1 = 1000;
Integer v2 = 1000;
boolean b1 = v1 == 1000; //True.
boolean b2 = v1 == v2; // out of range so it will false but if you use 127 instead of 1000 then it will true.
check the documentation here

Why can't I compare null field to a primitive [duplicate]

This question already has answers here:
Why comparing Integer with int can throw NullPointerException in Java?
(7 answers)
Closed 5 years ago.
Could you please tell me why I get a NullPointerException here?
public class N {
private Integer n = null;
public static void main(String... wargh) {
N obj = new N();
System.out.println(obj.n == 1);
}
}
The obj.n is (obviously!) null here, so obj.n == 1 must return false - just the same way as null == 1 returns false. But it does not. Instead, it throws an exception.
null cannot be compared to a primitive, since a primitive can never be equal to null.
null == 1 doesn't return false - it doesn't pass compilation.
Comparing an Integer to an int requires unboxing of the Integer into an int. obj.n == 1 throws NullPointException when obj.n == null, since unboxing obj.n is equivalent to executing obj.n.intValue().
Because obj.n == 1 is interpreted as primitive integer comparison, so obj.n will be auto-unboxed calling out.n.intValue(), which leads to the exception.
Formally, JLS 15.21 makes it clear that compiler knows your code is a numeric comparison, and then JLS 15.21.1 applies which states:
If the operands of an equality operator are both of numeric type, or one is of numeric type and the other is convertible (§5.1.8) to numeric type, binary numeric promotion is performed on the operands (§5.6.2).
Note that binary numeric promotion performs value set conversion (§5.1.13) and may perform unboxing conversion (§5.1.8).

Why comparing an Integer object with a primitive int throws null pointer exception when the Integer object is null in Java [duplicate]

It was very confusing to me to observe this situation:
Integer i = null;
String str = null;
if (i == null) { //Nothing happens
...
}
if (str == null) { //Nothing happens
}
if (i == 0) { //NullPointerException
...
}
if (str == "0") { //Nothing happens
...
}
So, as I think boxing operation is executed first (i.e. java tries to extract int value from null) and comparison operation has lower priority that's why the exception is thrown.
The question is: why is it implemented in this way in Java? Why boxing has higher priority then comparing references? Or why didn't they implemented verification against null before boxing?
At the moment it looks inconsistent when NullPointerException is thrown with wrapped primitives and is not thrown with true object types.
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 ==
Your NPE example is equivalent to this code, thanks to autoboxing:
if ( i.intValue( ) == 0 )
Hence NPE if i is null.
if (i == 0) { //NullPointerException
...
}
i is an Integer and the 0 is an int so in the what really is done is something like this
i.intValue() == 0
And this cause the nullPointer because the i is null. For String we do not have this operation, thats why is no exception there.
The makers of Java could have defined the == operator to directly act upon operands of different types, in which case given Integer I; int i; the comparison I==i; could ask the question "Does I hold a reference to an Integer whose value is i?"--a question which could be answered without difficulty even when I is null. Unfortunately, Java does not directly check whether operands of different types are equal; instead, it checks whether the language allows the type of either operand to be converted to the type of the other and--if it does--compares the converted operand to the non-converted one. Such behavior means that for variables x, y, and z with some combinations of types, it's possible to have x==y and y==z but x!=z [e.g. x=16777216f y=16777216 z=16777217]. It also means that the comparison I==i is translated as "Convert I to an int and, if that doesn't throw an exception, compare it to i."
It's because of Javas autoboxing feature. The compiler detects, that on the right hand side of the comparison you're using a primitive integer and needs to unbox the wrapper Integer value into a primitive int value as well.
Since that's not possible (it's null as you lined out) the NullPointerException is thrown.
In i == 0 Java will try to do auto-unboxing and do a numerical comparison (i.e. "is the value stored in the wrapper object referenced by i the same as the value 0?").
Since i is null the unboxing will throw a NullPointerException.
The reasoning goes like this:
The first sentence of JLS § 15.21.1 Numerical Equality Operators == and != reads like this:
If the operands of an equality operator are both of numeric type, or one is of numeric type and the other is convertible (§5.1.8) to numeric type, binary numeric promotion is performed on the operands (§5.6.2).
Clearly i is convertible to a numeric type and 0 is a numeric type, so the binary numeric promotion is performed on the operands.
§ 5.6.2 Binary Numeric Promotion says (among other things):
If any of the operands is of a reference type, unboxing conversion (§5.1.8) is performed.
§ 5.1.8 Unboxing Conversion says (among other things):
If r is null, unboxing conversion throws a NullPointerException
Simply write a method and call it to avoid NullPointerException.
public static Integer getNotNullIntValue(Integer value)
{
if(value!=null)
{
return value;
}
return 0;
}

Java - How can these 2 objects equal each other?

Hi I am revising and understand the difference between equals() and '==' however this code really confuses me:
public class MyTest {
public static void main(String[] args) {
Integer w = new Integer(1);
Integer x = 1;
double z = x;
System.out.println(z == w);
}
}
How can a double object have the same reference as an Integer object in memory when using '==' ? Cannot understand this. Thank you for reading!
If you compare primitive and wrapper using == operator, then the wrapper values will be un boxed and compared with primitive value.
From JLS 15.21.1
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 (§5.1.8) to
numeric type, binary numeric promotion is performed on the operands
(§5.6.2).
A double is not a reference, because it is a primitive type. It is a value instead. Double would have been a reference.
When you write z == w, where z is double-typed and w is Integer-typed, the runtime definitely has to compare something. And, obviously, it has to compare things of the same kind. It will not compare the double value with the Integer reference. Instead, it will unbox the Integer and will compare the int value obtained after unboxing with the double value. Both being 1, the boolean operator will return true.
Here objects are not compared but primitive types are compared with feature of unboxing for Integer.

Why comparing Integer with int can throw NullPointerException in Java?

It was very confusing to me to observe this situation:
Integer i = null;
String str = null;
if (i == null) { //Nothing happens
...
}
if (str == null) { //Nothing happens
}
if (i == 0) { //NullPointerException
...
}
if (str == "0") { //Nothing happens
...
}
So, as I think boxing operation is executed first (i.e. java tries to extract int value from null) and comparison operation has lower priority that's why the exception is thrown.
The question is: why is it implemented in this way in Java? Why boxing has higher priority then comparing references? Or why didn't they implemented verification against null before boxing?
At the moment it looks inconsistent when NullPointerException is thrown with wrapped primitives and is not thrown with true object types.
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 ==
Your NPE example is equivalent to this code, thanks to autoboxing:
if ( i.intValue( ) == 0 )
Hence NPE if i is null.
if (i == 0) { //NullPointerException
...
}
i is an Integer and the 0 is an int so in the what really is done is something like this
i.intValue() == 0
And this cause the nullPointer because the i is null. For String we do not have this operation, thats why is no exception there.
The makers of Java could have defined the == operator to directly act upon operands of different types, in which case given Integer I; int i; the comparison I==i; could ask the question "Does I hold a reference to an Integer whose value is i?"--a question which could be answered without difficulty even when I is null. Unfortunately, Java does not directly check whether operands of different types are equal; instead, it checks whether the language allows the type of either operand to be converted to the type of the other and--if it does--compares the converted operand to the non-converted one. Such behavior means that for variables x, y, and z with some combinations of types, it's possible to have x==y and y==z but x!=z [e.g. x=16777216f y=16777216 z=16777217]. It also means that the comparison I==i is translated as "Convert I to an int and, if that doesn't throw an exception, compare it to i."
It's because of Javas autoboxing feature. The compiler detects, that on the right hand side of the comparison you're using a primitive integer and needs to unbox the wrapper Integer value into a primitive int value as well.
Since that's not possible (it's null as you lined out) the NullPointerException is thrown.
In i == 0 Java will try to do auto-unboxing and do a numerical comparison (i.e. "is the value stored in the wrapper object referenced by i the same as the value 0?").
Since i is null the unboxing will throw a NullPointerException.
The reasoning goes like this:
The first sentence of JLS § 15.21.1 Numerical Equality Operators == and != reads like this:
If the operands of an equality operator are both of numeric type, or one is of numeric type and the other is convertible (§5.1.8) to numeric type, binary numeric promotion is performed on the operands (§5.6.2).
Clearly i is convertible to a numeric type and 0 is a numeric type, so the binary numeric promotion is performed on the operands.
§ 5.6.2 Binary Numeric Promotion says (among other things):
If any of the operands is of a reference type, unboxing conversion (§5.1.8) is performed.
§ 5.1.8 Unboxing Conversion says (among other things):
If r is null, unboxing conversion throws a NullPointerException
Simply write a method and call it to avoid NullPointerException.
public static Integer getNotNullIntValue(Integer value)
{
if(value!=null)
{
return value;
}
return 0;
}

Categories