I was going through some java interview questions MCQ where I found this code snippet, of which I didn't understand the output, though its only a 2 line code.
int a = 8;
System.out.println(((a<8)? 9.9 : (int)9));
Output is 9.0
I didn't understand why it is not 9 ?
Ternary operator has return type that is defined before the calculation of the value.
So, if the operator can return both float and int, then the both values are upcasted to the float.
Your answer is casted in this way:
(int)9 -> (int)9 -> (float)9.
Other situation: If you add float and int, you get float
int a = 2;
float b = 4.3f;
float c = a + b;
Because you are not casting all of them . you are just casting second result to int.
But don't forget first result is float so all of structure must be same type.
You need to cast all of them as same type like int or float.
int a = 8;
System.out.println(""+ (int)( (a<8)? 9.9 : 9));
output :
9
The return type of the ternary operator is determined according to quite complicated rules:
Java Language Specification. Specifically, in your case:
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.
So in your case you get return type double.
Related
If I have Ternary syntax like this, compiler does not throw any compilation error:
int s = 2;
Double sdf = (s > 3 ? new Double(12) : new Integer(12));
However if I have this, it is throwing compilation error:
Required type: Double Provided: Integer
Double sdf = (s > 3 ? new Integer(12) : new Integer(12));
This happens because if we use wrapped primitive values like in the question (Integer, Float, Double etc.) in a ternary operator, both values will be unboxed and coerced to a common type.
This may result in unexpected results as well.
In the first example, new Integer(12) would be converted to a double as it is the common type. Hence there are no compilation issue.
But in the second example both are Integer which is not compatible with the left hand side type Double.
Example taken from Sonar rule description S2154:
Integer i = 123456789;
Float f = 1.0f;
// Assume condition = true
Number n = (condition) ? i : f; // i is coerced to float. n = 1.23456792E8
To fix this, we need to do explicit casting:
Integer i = 123456789;
Float f = 1.0f;
// Assume condition = true
Number n = condition ? (Number) i : f; // n = 123456789
Additional suggestion: Do not use new Double() or new Integer() etc. These constructors are deprecated. Instead use valueOf method
According to the Conditional Operator ? : specification, in case if one operand is Integer and the other is Double binary numeric promotion is used to resolve the result type.
Based on the rules, in the first example, the result type is Integer but Double in the second one (unboxing + widening).
It's because internally type is pramoted. Integer can be pramoted to double. But double can't be demoted to Integer.
Pramotion happens in following way
Byte -->Short-->Interger-->Long-->Float -->Double
See screenshot:
What is going on there? i see that we're casting 23F to an int so in choice "II", we wind up doing 23/7 which should give us 3... at least so I thought. But why do we have 3.0? Why do we get a double?
Here is the context:
float x = myFunc(23F);
int myFunc(float x) { ... }
The right hand side of the expression is an int and you have correctly deduced that its value is 3.
When you assign an int value to a float variable, the integer will be converted to a float.
This is an example of a primitive widening conversion. It can happen in various contexts when you are going from a "smaller" primitive numeric type to a "larger" primitive numeric type. The int type is "smaller" than the float type. In general:
byte < short and char < int < long < float < double.
Why do we get a double?
See above. But it is a float not a double.
When you output a number in Java using println, a float and a double will look the same. The println method won't output a float with an F suffix. The F and D suffixes are only used in Java source code.
Because the function that return the result is assigned to z, and the type of z is float.
recently I learned about the two's compliment method of representing both positive and negative integers in the base two system. I then tried to see this in action using java with the following short code:
int a=2147483647;
System.out.println("a: "+a);
System.out.println("a+1: "+(a+1));
short b=32767;
System.out.println("b: "+b);
System.out.println("b+1: "+(b+1));
Which outputs:
a: 2147483647
a+1: -2147483648
b: 32767
b+1: 32768
Which confuses me because I would think that b+1, being represented in binary as 011111111111111, would turn into 1000000000000000, or in decimal, -32768. What's going on?
Although b is a short, the expression (b + 1) is an int. The right operand is an int, the left operand is promoted to an int, and the expression is the promoted type of the operands.
From the Java Language Specification, 5.6.2. 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.
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.
Note that this last promotion occurs even if both operands are of short type. You can't avoid promotion to an int with (b + (short) 1).
From 15.18.2. Additive Operators (+ and -) for Numeric Types
The type of an additive expression on numeric operands is the promoted type of its operands.
No need for confusion, try this:
short b = 32767;
short c = b + 1;
What do you get? Right, you get:
error: incompatible types: possible lossy conversion from int to short
short c = b + 1;
So, what happens at your line?
System.out.println("b+1: "+(b+1));?
Well, b+1 is too big for short, as you said correctly, but here you add an int to it, making the result an int as well. And 32768 is a valid int.
As others already pointed out, if you explicitly cast it down to (short) you get what you asked for.
On the other hand that does not work for short c = b + 1; as here the declared type is a short, while the actual type is an int.
short c = (short) (b + 1); solves that "problem"
doing + automatically promotes short to int. Do this and you will see the overflow.
System.out.println("b+1: "+(short)(b+1)); //-32768
From the Java Language Specification, 5.6.2. 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.
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.
Notice the last rule, so essentially that means that even if they are both shorts, they will be promoted to int, this can't be avoided.
you could:
short b= 32767;
short d= 12;
System.out.println("b+1: "+ (d+b)); // 32779
And the answer would still be valid.
1 is an int literal. When you compute b+1, you in fact promote b to an int and then add 1, resulting in 32768, which is a perfectly legal int value. If you cast it down to a short again, you'll see the overflow you're expecting (-32768):
System.out.println("b+1: " + (short)(b + 1));
As others have noted, addition promotes the operands to int.
Note that the += operator automatically does the casting back to short:
short b=32767;
System.out.println(b + 1); // 32768, because of integer promotion.
b += 1; // Equivalent to b = (short)(b + 1);
System.out.println(b); // -32768
b++;/++b; would yield the same result as b += 1.
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.
}
I'm wondering why there is an inconsistency with the code below. I would expect the same output, but when using the inline conditional statement, it appends a .0 to the string.
Do I have some error in my code?
double d = 10.1;
String rounded = (false ? d : Math.round(d)) + "";
System.out.println(rounded);//10.0
rounded = Math.round(d) + "";
System.out.println(rounded);//10
Math.round returns a long, therefore the two operands of the conditional operator do not have the same type, and thus a more complex rule is followed to determine the type of the overall operation, as defined in JLS §15.25:
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).
And from 5.6.2, binary numeric promotion:
If either operand is of type double, the other is converted to double.
And to illustrate the pitfalls with the conditional operator and for some fun, from Java puzzlers (puzzle 8):
char x = 'X';
int i = 0;
System.out.print(true ? x : 0); // prints X
System.out.print(false ? i : x); // prints 88 => (int)X
Also, check out the Hamlet and Elvis examples (video links).
The type returned from a ternary operator may be promoted so that the two potential return types match. This is called binary numeric promotion, and your variable is being promoted from long to double before conversion to a String.
If you had this where both potential return types are int or long:
double d = 10.1;
String rounded = (false ? 0 : Math.round(d)) + "";
What happens (not a rhetorical question since I'm no where near a Java compiler)?