Ternary operator - java

Why the output of following code is 9.0 and not 9 ? If ternary operator is nothing but short form of if-else branch then why java compiler is promoting int to double ?
public class Ternary
{
public static void main(String args[])
{
int a = 5;
System.out.println("Value is - " + ((a < 5) ? 9.9 : 9));
}
}

If ternary operator is nothing but short form of if-else branch then why java compiler is promoting int to double ?
A conditional expression has a single type, which both the second and third operands are converted to as necessary. The JLS gives the rules determining the expression type, which are slightly complicated due to auto-unboxing.
The conditional operator is sort of just shorthand for an if/else construct, but not the sort of shorthand I think you expected. So your code is equivalent to this:
double value;
if (a < 5) {
value = 9.9;
} else {
value = 9;
}
System.out.println("Value is - " + value);
It's not short for:
if (a < 5) {
System.out.println("Value is - " + 9.9);
} else {
System.out.println("Value is - " + 9);
}
For more details, see section 15.25 of the Java Language Specification.

Because the type of the conditional operator(Yes, it's conditional operator and not ternary operator) in this case will be the promoted type of the 3rd operand, since 2nd and 3rd operand are not of same type.
This is clearly listed in JLS Secion - 15.25: -
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 (§15.28) 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 T, where T is Byte, Short, or
Character, and the
other operand is a constant expression (§15.28) of
type int whose value is representable in the type U which is the
result of applying unboxing conversion to T, then the type of the
conditional expression is U.
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.
See the last point, that is of use here. So, in this case, as a rule of binary numeric promotion - See JLS Section 5.6.2: -
If either operand is of type double, the other is converted to double.

Because the type of the expression as a whole is double, because one of the operands to the operator is a double. The type of the expression containing the ternary is dictated by the operands, which must be of the same type. In the case of your expression, the 9 is coerced to a double to make it the same type as the 9.9.

Actually the ternary operator is not strictly speaking a short form of if/else as it does perform type conversion if required. In particular, in your case, JLS 15.25 requires that:
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.
If you follow the link to §5.6.2:
If either operand is of type double, the other is converted to double.

Java needs to know the type of the result at compile time. So as this ternary operator can result an int or a double, the compiler chooses the double as the result type.

Related

Data types and variables java [duplicate]

This question already has an answer here:
Why byte and short values are promoted to int when an expression is evaluated [duplicate]
(1 answer)
Closed 7 years ago.
When we do addition,subtractions,divide(etc..)in byte short data types the result is coming from int value...why is that...?
e.g:- in above code does not compile because the result in c is coming from int why is that happen...??? when we try to print c using system out it came error because result is in int
public class A {
public static void main(String[] args) {
byte a = 12;
byte b = 10;
byte c = a + b;
System.out.println(c);
}
}
According to java doc the when we perform operations on two bytes there is probability that the output would be a number which can't be handled by byte, so it was decided by creators of java to auto cast it to Integer. So it's like this.
This is well answered here, starting from an identical scenario :) http://www.coderanch.com/t/499127/java/java/Adding-bytes
To quote http://java.sun.com/docs/books/jls/third_edition/html/conversions.html#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.
The spec says:
https://docs.oracle.com/javase/specs/jls/se7/html/jls-15.html#jls-15.18.2
The binary + operator performs addition when applied to two operands of numeric type, producing the sum of the operands.
The binary - operator performs subtraction, producing the difference of two numeric operands.
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).
The type of an additive expression on numeric operands is the promoted type of its operands.
https://docs.oracle.com/javase/specs/jls/se7/html/jls-5.html#jls-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:
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.
If you combine the two you see that any operand in an addition will be promoted to either int or long and any primitive smaller than int will be promoted to int. The result of the operation is the type of both operands - which it int.
The reasoning behind that is most probably that int is the most common datatype which reduces probability of overflow while not requiring as much space as a long. The space argument probably isn't as generally valid as it used to be anymore but that part of the spec was defined like in 1995 and an inherent part of the language (which you can't change without breaking compatibility).
Any Binary arithmetic operations we performed on char & byte datatype(and short) promote it to int.
For more details please refer JLS 5.6.2.
This works:
final byte a = 12;
final byte b = 10;
byte c = a + b;
Or this:
byte a = 12;
byte b = 10;
byte c = (byte)( a + b);

Weird behaviour of ternary conditional with boxed types in Java [duplicate]

This question already has answers here:
Why does the ternary operator unexpectedly cast integers?
(3 answers)
Closed 7 years ago.
I had this piece of code in my application (simplified version):
Object result;
if (check)
result = new Integer(1);
else
result = new Double(1.0);
System.out.println(result);
return result;
Then I decided to refactor the if-else statement to a ternary conditional expression so my code is more concise:
Object result = check ? new Integer(1) : new Double(1.0);
System.out.println(result);
return result;
It turned out that in case check is true the two versions print different results:
1
or:
1.0
Isn't the ternary conditional equivalent to the corresponding if-else?
The if/else and the conditional (ternary) expression are not quite equivalent. The result of the conditional expression must have a type.
You're observing the effects of numeric type promotion (or type coercion).
Here's an excerpt from the language spec (see here), from the section describing the return value of the conditional expression:
Otherwise, if the second and third operands have types that are convertible (§5.1.8) to numeric types, then there are several cases:
The final such case is (I've omitted the other cases here):
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.
Here's the additional spec related to binary numeric promotion:
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.
It's the first case (following cases omitted). double always wins.
So regardless of the order of the 2nd and 3rd operands in your conditional expression, the return type of the expression will be promoted to double.
Put simply, the ternary operator isn't different from other operators where numeric type promotion is concerned.
When you have something like System.out.println(1 + 1.0), you expect it to print 2.0, because the operands used in the output are subject to numeric type promotions.
It's exactly the same with the ternary operator: System.out.println(true ? 1 : 1.0) will print 1.0 after doing the same numeric type promotions it would have done if the expression was 1 + 1.0.
It works that way for a very simple reason: the type of the operator's result should be known at compile-time, while its actual result is determined at run-time.
Short answer
The first example explicitly typed as Object, which causes an upcast.
The second example is implicitly typed as Double, which causes numeric widening.
Long answer
In the example with Object, there is no conversion of values, just an upcast, and 1 is printed.
Object result;
if (1 == 1)
result = new Integer(1);
else
result = new Double(1.0);
If you instead declared using Double, it would be a widening and print 1.0.
Double result;
if (1 == 1)
result = new Integer(1);
else
result = new Double(1.0);
These are rather straightforward since there is an explicit type.
The ternary expression, however, has no explicit type, and the rules are non-trivial.
The type of a conditional expression is determined as follows:
If the second and third operands have the same type (which may be the null type), then that is the type of the conditional expression.
If one of the second and third operands is of primitive type T, and the type of the other is the result of applying boxing conversion (§5.1.7) to T, then the type of the conditional expression is T.
If one of the second and third operands is of the null type and the type of the other is a reference type, then the type of the conditional expression is that reference type.
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 (§15.28) 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 T, where T is Byte, Short, or Character, and the other operand is a constant expression (§15.28) of type int whose value is representable in the type U which is the result of applying unboxing conversion to T, then the type of the conditional expression is U.
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).
Otherwise, the second and third operands are of types S1 and S2 respectively. Let T1 be the type that results from applying boxing conversion to S1, and let T2 be the type that results from applying boxing conversion to S2. The type of the conditional expression is the result of applying capture conversion (§5.1.10) to lub(T1, T2) (§15.12.2.7).
http://docs.oracle.com/javase/specs/jls/se7/html/jls-15.html#jls-15.25
The "promoted type" of numerics Integer and Double is Double.
In addition to #pb2q answer
you can verify it as
public class test {
public static void main(String[] args) {
Object result;
Boolean check = true;
if (check)
result = new Integer(1);
else
result = new Double(1.0);
System.out.println(result);
result = check ? new Integer(2) : new Double(1.0);
System.out.println(result);
}
}
it will print 2.0 instead of 2 because of numeric promotion
In addition to the existing answers, you can avoid the problem by specific casting to the type you want:
Object result = args.length < 100 ? (Object)2 : (Object)1.0;
Casting to Object boxes the integer as an Integer, and the double as a Double. The expressions on either side of the ":" are then both of type Object, so the compiler does not need to generate any further conversions.

Java - char, int conversions

In Java, the following is allowed:
char c = 'A' + 1;
Here, c will hold the value 'B'. Above, first the expression is evaluated. So 'A' gets converted to 65, the whole expression evaluates to 66, and then 66 is converted to 'B' since we are storing the value in a char.
The following, however, gives a compile-time error:
char c = 'A';
c = c + 1;
What is the explanation for how Java views the expressions differently? By the way, the following works fine too:
char c = 'A';
c++;
The first example (which compiles) is special because both operands of the addition are literals.
A few definitions to start with:
Converting an int to char is called a narrowing primitive conversion, because char is a smaller type than int.
'A' + 1 is a constant expression. A constant expression is (basically) an expression whose result is always the same and can be determined at compile-time. In particular, 'A' + 1 is a constant expression because the operands of + are both literals.
A narrowing conversion is allowed during the assignments of byte, short and char, if the right-hand side of the assignment is a constant expression:
In addition, if the expression [on the right-hand side] is a constant expression of type byte, short, char, or int:
A narrowing primitive conversion may be used if the variable is of type byte, short, or char, and the value of the constant expression is representable in the type of the variable.
c + 1 is not a constant expression, because c is a non-final variable, so a compile-time error occurs for the assignment. From looking at the code, we can determine that the result is always the same, but the compiler isn't allowed to do that in this case.
One interesting thing we can do is this:
final char a = 'a';
char b = a + 1;
In that case a + 1 is a constant expression, because a is a final variable which is initialized with a constant expression.
The caveat "if […] the value […] is representable in the type of the variable" means that the following would not compile:
char c = 'A' + 99999;
The value of 'A' + 99999 (which is 100064, or 0x186E0) is too big to fit in to a char, because char is an unsigned 16-bit integer.
As for the postfix ++ operator:
The type of the postfix increment expression is the type of the variable.
...
Before the addition, binary numeric promotion* is performed on the value 1 and the value of the variable. If necessary, the sum is narrowed by a narrowing primitive conversion and/or subjected to boxing conversion to the type of the variable before it is stored.
(* Binary numeric promotion takes byte, short and char operands of operators such as + and converts them to int or some other larger type. Java doesn't do arithmetic on integral types smaller than int.)
In other words, the statement c++; is mostly equivalent to:
c = (char)(c + 1);
(The difference is that the result of the expression c++, if we assigned it to something, is the value of c before the increment.)
The other increments and decrements have very similar specifications.
Compound assignment operators such as += automatically perform narrowing conversion as well, so expressions such as c += 1 (or even c += 3.14) are also allowed.
char to int conversion is called widening conversions. In widening conversions, values do not lose information about the overall magnitude of a numeric value where as int to char conversion is called narrowing conversions. With narrowing conversion you may lose information about the overall magnitude of a numeric value and may also lose precision.
For more information on primitive conversions refer this document.
It is because the compiler can check that it ('A' + 1) is within the bounds of a char whereas it cannot (in general) check that c + <an integer> is within the bounds.
Its because the literals for integer or smaller than int as byte ,short and char is int. Understand the following in this way.
code:
byte a = 10;//compile fine
byte b= 11;//compile fine
byte c = a+b;//compiler error[says that result of **a+b** is **int**]
the same happens for any mathematical operations as of 'Divide', 'multiply', and other arithmetic operation. so cast the result to get the literal in desired data type
byte c = (byte)(a+b);
so when you perform
c= c+1;//compiler error
Its the result of c+1 is int not a char . so compiler give a compile time error for the same.
so you need to provide a primitive cast to change the literal to char data type.
Hope this example provide some understanding..

Strange java behaviour with conditional operator. Is it a bug?

Can you please run the below and explain?
Object o = true ? new Integer(1) : new Double(2.0);
System.out.println(o);
I found that surprising as someone would expect 1 to be printed and not 1.0
It's not a surprise at all, although it might seem like one. The behaviour is specified in JLS §15.25 - 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:
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.
[...]
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).
So the Integer and Double types are unboxed to their respective primitive counterparts - int and double, as a process of binary numeric promotion. And then the type of the conditional operator is the promoted type of int and double, which is double. Hence the result is 1.0. And of course the final result is then boxed back to Double.
Here is an article published in DZone yesterday talking about it:
Java auto unboxing gotcha
Funny enough, the example code looks similar...

Output different from what i have expected

Why its printing X88
public static void main(String [] args)
{
char x = 'X';
int i = 0;
System.out.print(true ? x : 0);
System.out.print(false ? i : x);
}
In the first print statement, the type of the conditional expression is char (i.e. 'X') because this part of section 15.25 of the JLS (which is about the type of a conditional expression) applies:
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.
So the first statement prints "X".
In the second print statement, that part doesn't apply because i isn't a constant expression. Instead, this section applies:
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).
Binary numeric promotion converts the char 'X' to an int (88) and the second statement prints "88" - hence the overall result of "X88".
It's explained in §15.25 of the JLS.
Otherwise, if the second and third
operands have types that are
convertible (§5.1.8) to numeric types,
then there are several cases:
This applies to both statements, since both char and int are numeric types, and thus 5.1.8 trivially applies. So we look at the rules below (excerpted):
[...]
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.
This applies to the first, since 0 is a constant expression of type int. T is , char, which is why it prints as X.
[...]
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).
This applies to the second, since nothing else does. :) The relevant rule from §5.6.2 is simply:
Otherwise, both operands are converted to type int.
The Unicode code point for 'X' is 88.
For the first statement System.out.print(false ? x : 0); the compiler thinks that you want to print a char so 0 will be considered as a char (during compilation).
When you do System.out.print(false ? i : x); the compiler thinks that you want to print an integer, so it will try to convert (widen) 'X' into an integer which is 88.
An interesting thing is that if you try to do this :
System.out.print(true ? x : i);
As i cannot be considered as a char (it would require narrowing) it will print 88
Another thing which is interessant here :
System.out.print(true ? x : 65536);
This time the value 65536 can't be considered as a char at compile time (the max value for a char is 65535 [#See Character.MAX_VALUE]) so it will be considered as an int, so x will be too.
To summarize, if one of the operand is an int and the other a char, there are two possible conversions :
The int is narrowed into a char (loss of precision)
The char is widen into an int (no loss of precision)
To avoid useless loss, Java will chose the second option.
When you do System.out.print(false ? x : 0);, the 0 is converted at compilation time into a char (because the compiler knows that there won't be loss of precision).
Resources :
JLS - Widening Primitive Conversion
Because the expression false ? i : x is being seen as returning an integer by the compiler. Since you are using a char the 'X' is 88 in ASCII and it is being seen as an integer since they are compatible.
Personally, I think there should be at least a compiler warning here.
In the second ternary If, the parameters must be of the same type, otherwise one of the two is implicitly converted.
In your example, x is converted from char to int, and 'X' has an ASCII code of 88.
Others have already answered why this happens.
If you want X to be printed, cast the expression value back to char as:
System.out.print((char)(false ? i : x)); // prints X
or you can also cast i to char so that the type of expression becomes char as:
System.out.print(false ? (char)i : x); // prints X

Categories