In the following code I have two identical conditional assignment operations, one returns an object of type Double, and the second returns the String "Integer".
double d = 24.0;
Number o = (d % 1 == 0) ? new Double(d).intValue() : new Double(d).doubleValue();
String result = (d % 1 == 0) ? "Integer" : "Double";
System.out.println(o.getClass()); // prints "class java.lang.Double"
System.out.println(result); // Integer
Why are the exact same expressions returning two different things?
Well, that is because of the JLS specs for the conditional operator:
Otherwise, if the second and third operands have types that are convertible (§5.1.8) to numeric types, then there are several cases:
...
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.
Numeric promotion is defined here in §5.6.2. It says:
Widening primitive conversion (§5.1.2) is applied to convert either or
both operands as specified by the following rules:
If either operand is of type double, the other is converted to double.
...
Well 0.0 is still == to 0
System.out.println(0 == 0.0); // equals true
http://docs.oracle.com/javase/specs/jls/se7/html/jls-15.html#jls-15.25
Related
I read that compiler refuses to use auto boxing/unboxing when there is more than one operation needed in order to perform implicit conversion (int -> double -> Double or Integer -> int -> double). It's stil rather confusing
Integer i = 2;
Double d = 2.0;
System.out.println(i == d); // COMPILE TIME ERROR
// fix
System.out.println( (double) i == d); // OK: true
My understanding is that the compiler tries to unwrap i with Integer.intValue(). Since it takes more than one step to convert Integer to double (Integer -> int -> double) compiler refuses to do it implicitly, so we need to "help him" by using explicit type conversion, which will reduce the number of steps. Is it correct?
Integer i = 2;
double d = 2.0;
System.out.println(i == d); // OK: true
In this example it clearly takes more than one step for the compiler to perform conversion (Integer -> int -> double). How come it doesn't complain?
I'm aware that one must use equals() method over ==
The answer can be found in the Java Language Specification, in section 15.21. Equality Operators:
The operators == (equal to) and != (not equal to) are called the equality operators.
Section 15.21.1. Numerical Equality Operators == and != 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 (§5.6).
Section 15.21.3. Reference Equality Operators == and != says:
If the operands of an equality operator are both of either reference type or the null type, then the operation is object equality.
It is a compile-time error if it is impossible to convert the type of either operand to the type of the other by a casting conversion (§5.5). The run-time values of the two operands would necessarily be unequal (ignoring the case where both values are null).
Without a cast, the i == d expression must follow the rules in section 15.21.3, because both i and d are reference types, not numeric types. Only the primitive types are numeric types (except boolean of course).
Since an Integer cannot be cast to a Double, and a Double cannot be cast to an Integer, the compiler knows that it is impossible for the expression to be true (ignoring the case where both values are null), so a compile-type error occurs.
When you do (double) i == d, then the left-hand side becomes a numeric type, and the rules specified in section 15.21.1 applies.
This question already has answers here:
Why don't Java's +=, -=, *=, /= compound assignment operators require casting?
(11 answers)
Adding int to short [duplicate]
(3 answers)
short plus short is an int [duplicate]
(2 answers)
Closed 4 years ago.
I just can't understand the difference between this:
short d = 0;
//some code
node.accessible = d + 1;
and this
short d = 0
//same code here
node.accessible = d;
node.accessible += 1;
the second thing is working, but the 1st one is't inteliji showes "incompatiable types" error.
p.s. node class:
public class Node {
int n;
short accessible;
Node(int n){
this.n = n;
this.accessible = -1;
}
}
In the first version :
node.accessible = d + 1;
d + 1 produces a int as summing an int and a short produces an int.
The JLS states indeed that (look at the last case, emphasis is mine) :
5.6.2. Binary Numeric Promotion
When an operator applies binary numeric promotion to a pair of
operands, each of which must denote a value that is convertible to a
numeric type, the following rules apply, in order:
If any operand is of a reference type, it is subjected to unboxing
conversion (§5.1.8).
Widening primitive conversion (§5.1.2) is applied to convert either or both operands as specified by the following rules:
If either operand is of type double, the other is converted to double.
Otherwise, if either operand is of type float, the other is converted
to float.
Otherwise, if either operand is of type long, the other is converted
to long.
Otherwise, both operands are converted to type int.
But you cannot assign a int to the accessible field that is a short without explicit cast as int has a broader range than short.
While in the second version, a Compound Assignment Operators is used (+=):
node.accessible += 1;
As a consequence, in your case the result of the operation is converted to short : the type of the left-hand variable as the JLS states :
15.26.2. Compound Assignment Operators
A compound assignment expression of the form E1 op= E2 is equivalent
to E1 = (T) ((E1) op (E2)), where T is the type of E1, except that E1
is Evaluations only once.
And more specifically in your case :
Otherwise, the result of the binary operation is converted to the type
of the left-hand variable, subjected to value set conversion (§5.1.13)
to the appropriate standard value set (not an extended-exponent value
set), and the result of the conversion is stored into the variable.
That's because 1 in your + 1 expression is of type int. Adding short to int results in int which can't be assigned without a narrowing cast back to node.accessible.
In the second sample,
node.accessible += 1;
is actually
node.accessible = (short)(node.accessible + 1);
so it works without problem.
But in the first one
node.accessible = d + 1; is actually node.accessible = d + 1; and it doesn't automatically cast as short and thus gives error as (d + 1) is of type int
I have seen it discussed somewhere that the following code results in obj being a Double, but that it prints 200.0 from the left hand side.
Object obj = true ? new Integer(200) : new Double(0.0);
System.out.println(obj);
Result: 200.0
However, if you put a different object in the right hand side, e.g. BigDecimal, the type of obj is Integer as it should be.
Object obj = true ? new Integer(200) : new BigDecimal(0.0);
System.out.println(obj);
Result: 200
I presume that the reason for this is something to do with casting the left hand side to a double in the same way that it happens for integer/double comparisons and calculations, but here the left and right sides do not interact in this way.
Why does this happen?
You need to read section 15.25 of the Java Language Specification.
In particular:
Otherwise, if the second and third operands have types that are convertible (§5.1.8) to numeric types, then there are several cases:
If one of the operands is of type byte or Byte and the other is of type short or Short, then the type of the conditional expression is short.
If one of the operands is of type T where T is byte, short, or char, and the other operand is a constant expression of type int whose value is representable in type T, then > - the type of the conditional expression is T.
If one of the operands is of type Byte and the other operand is a constant expression of type int whose value is representable in type byte, then the type of the conditional expression is byte.
If one of the operands is of type Short and the other operand is a constant expression of type int whose value is representable in type short, then the type of the conditional expression is short.
If one of the operands is of type; Character and the other operand is a constant expression of type int whose value is representable in type char, then the type of the conditional expression is char.
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 unboxing conversion (§5.1.8) and value set conversion (§5.1.13).
So binary numeric promotion is applied, which starts with:
When an operator applies binary numeric promotion to a pair of operands, each of which must denote a value that is convertible to a numeric type, the following rules apply, in order, using widening conversion (§5.1.2) to convert operands as necessary:
If any of the operands is of a reference type, unboxing conversion (§5.1.8) is performed. Then:
If either operand is of type double, the other is converted to double.
That's exactly what happens here - the parameter types are converted to int and double respectively, the second operand (the third in the original expression) is then of type double, so the overall result type is double.
Numeric conversion in the conditional operator ? :
In the conditional operator a?b:c, if both b and c are different numeric types, the following conversion rules are applied at compile time to make their types equal, in order:
The types are converted to their corresponding primitive ones, which is called unboxing.
If one operand were a constant int (not Integer before unboxing) whose value is representable in the other type, the int operand is converted into the other type.
Otherwise the smaller type is converted into the next greater one until both operands have the same type. The conversion orders are:
byte -> short -> int -> long -> float -> double
char -> int -> long -> float -> double
Eventually the whole conditional expression gets the type of its second and third operands.
Examples:
If you combine char with short, the expression becomes int.
If you combine Integer with Integer, the expression becomes Integer.
If you combine final int i = 5 with a Character, the expression becomes char.
If you combine short with float, the expression becomes float.
In the question's example, 200 is converted from Integer into double, 0.0 is unboxed from Double into double and the whole conditional expression becomes becomes double which is eventually boxed into Double because obj is of type Object.
Example:
public static void main(String[] args) {
int i = 10;
int i2 = 10;
long l = 100;
byte b = 10;
char c = 'A';
Long result;
// combine int with int result is int compiler error
// result = true ? i : i2; // combine int with int, the expression becomes int
//result = true ? b : c; // combine byte with char, the expression becomes int
//combine int with long result will be long
result = true ? l : i; // success - > combine long with int, the expression becomes long
result = true ? i : l; // success - > combine int with long, the expression becomes long
result = true ? b : l; // success - > combine byte with long, the expression becomes long
result = true ? c : l; // success - > char long with long, the expression becomes long
Integer intResult;
intResult = true ? b : c; // combine char with byte, the expression becomes int.
// intResult = true ? l : c; // fail combine long with char, the expression becomes long.
}
This question already has answers here:
Ternary operator casts integer
(3 answers)
Closed 5 years ago.
I recently come accross the scenario where in first syso() charcter is working fine but in second syso() it is printing ASCII code.
public class Test{
public static void main(String[] args) {
char x = 'A';
char y= 'B';
int m = 0;
System.out.println(true ? x : 0);//Working fine prints A
System.out.println(true ? y : 0);//Working fine prints B
System.out.println(false ? 0 : y);//Working fine prints B
System.out.println(false ? m : x);// Here it prints 65 why ?
}
}
I really want to know why it is printing ascii code in second syso() ? Please help
The issue is in the type of false ? m : x, which ends up being int, not char.
As per JLS section 15.25.2 (emphasis and [] note mine):
The type of a numeric conditional expression is determined as follows:
If the second and third operands have the same type, then that is the type of the conditional expression.
...
Otherwise [if none of the above rules hold], 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.
Where binary numeric promotion's relevant rule is (emphasis mine):
Widening primitive conversion (§5.1.2) is applied to convert either or both operands as specified by the following rules:
If either operand is of type double, the other is converted to double.
Otherwise, if either operand is of type float, the other is converted to float.
Otherwise, if either operand is of type long, the other is converted to long.
Otherwise, both operands are converted to type int.
Therefore in:
char x = ...;
int m = ...;
The expression condition ? m : x is promoted to int, and System.out.println(int) is called, and it prints it as a number.
You'd have to explicitly cast m or the whole expression to a char, e.g.:
System.out.println((char)(false ? m : x));
Or:
System.out.println(false ? (char)m : x);
As for your condition ? x : 0 and condition ? 0 : x forms, one of the rules (that I omitted above) from 15.25.2 is:
If one of the operands is of type T where T is byte, short, or char, and the other operand is a constant expression (§15.28) of type int whose value is representable in type T, then the type of the conditional expression is T.
0 fits this description. x is a char, 0 fits in a char, the type of the conditional is therefore char and the character is printed.
I was just playing around with type casting. Here's the code:
class Typecasting {
public static void main(String[] args) {
byte b = 3;
byte c = b++; // no error
byte d = b + 1; // error
byte e = b + b; // error
}
}
Why is there no error in the first line but in second?? Also when i do
f = b + 2;
I understand that b was automatically cast into int type and therefore f must be int type but when I do
e = b + b;
they both are byte type and their result is also in the range of a byte, so why can't e have byte data type? Is it due to the + binary operator?
Why is there no error in the first line but in second?
Because that's the way the language is defined. There's no byte + byte operator, which is why the third line fails - both operands are promoted to int automatically. From section 15.18.2 of the JLS:
The binary + operator performs addition when applied to two operands of numeric type, producing the sum of the operands.
...
Binary numeric promotion is performed on the operands (§5.6.2).
Now binary numeric promotion always ends up with a value of int, long, float or double... int in this case. So the operation is to add two int values together, and the result is an int.
For b++, however, the type is still byte. It's a postfix increment expression (section 15.14.2):
The type of the postfix increment expression is the type of the variable.
On a related note, this would be okay:
b += 3;
That's a compound assignment (section 15.26.2):
A compound assignment expression of the form E1 op= E2 is equivalent to E1 = (T) ((E1) op (E2)), where T is the type of E1, except that E1 is evaluated only once.
Note the casting part, which is why it works.
+(byte, byte) returns an int per the rules of the language.
The relevant section of the spec is §5.6.2:
When an operator applies binary numeric promotion to a pair of operands, each of which must denote a value that is convertible to a numeric type, the following rules apply, in order, using widening conversion (§5.1.2) to convert operands as necessary:
If any of the operands is of a reference type, unboxing conversion (§5.1.8) is performed. Then:
If either operand is of type double,the other is converted to double.
Otherwise, if either operand is of type float, the other is converted to float.
Otherwise, if either operand is of type long, the other is converted to long.
Otherwise, both operands are converted to type int.
Whereas for ++, the type of the result is the type of the operand. From the JLS, §15.14.2:
The type of the postfix increment expression is the type of the variable.
Thus, for b++, the result is a byte and so is assignable to c.
byte d = b+1;
In here you are assign int value(b+1) to byte d. When you added a int vale to byte value it becomes int value.
byte c = b++; //No error;First Line
This conforms to JLS 15.14.2
The type of the postfix increment expression is the type of the variable. The result of the postfix increment expression is not a variable, but a value.
byte d = b+1; //error;Second Line
byte e = b+b; //error;Third line
This conforms to JLS 15.18.2
The binary + operator performs addition when applied to two operands of numeric type, producing the sum of the operands.
The type of an additive expression on numeric operands is the promoted type of its operands.
If this promoted type is int or long, then integer arithmetic is performed.
Read about type promotion in JLS 5.6.2
Widening primitive conversion (§5.1.2) is applied to convert either or both operands as specified by the following rules:
If either operand is of type double, the other is converted to double.
Otherwise, if either operand is of type float, the other is converted to float.
Otherwise, if either operand is of type long, the other is converted to long.
Otherwise, both operands are converted to type int.
in line first ++operator returns always operand type result..so it gives no error
in second line here 1 is an integer type because all integer type literals is int by default
in third line +(byte,byte) returns the integer type that why it will forces you to type cast it into int.
--> in third line there is always a probability to overflow in byte type..
* if your byte type is defined as constant then it will not force you to typecast because it will alwayz be in range.
When Java performs a sum, it first "transforms" both operands to int or long (depending of the operands) and the result will be an integer, which will try to assign to your variable of type byte, as it "realizes" the result wont fit in a byte, then it will "complain" and you wont be even able to compile this.