Scroll to the bottom of my answer to see what the actual javac source code does :)
The Bytecode Generated
@zapl's answer definitely answers the specific question, but I feel like the OP's question still wasn't answered. How exactly does JVM compile ternary operators? So, I just want to answer that question for everyone wondering.
We can figure this out by looking at the actual bytecode generated. So, I created a test where I have two outside classes that have some static variable I'm referencing, and all that, but that's still besides the point because we just want to know if it compiles it the same way as an if-else. Regardless, I did a test with ternary and with the equivalent if-else and these are the results.
Java Code:
class main {
public static void main(String[] args) {
int a = 0;
int b = 2;
int c = a > b ? MyBigClass.VAR_1 : MyOtherBigClass.VAR_2;
//int c;
// if (a > b) {
// c = MyBigClass.VAR_1;
// } else {
// c = MyOtherBigClass.VAR_2;
// }
}
}
class MyBigClass {
public static int VAR_1 = 0;
}
class MyOtherBigClass {
public static int VAR_2 = 1;
}
As you can see I commented out the if-else for the test with the ternary, and then I just commented out the ternary when I was testing the if-else. The bytecode that resulted was this.
Bytecode using if-else:
public static void main(java.lang.String[]);
Code:
0: iconst_0
1: istore_1
2: iconst_2
3: istore_2
4: iload_1
5: iload_2
6: if_icmple 16
9: getstatic #2 // Field MyBigClass.VAR_1:I
12: istore_3
13: goto 20
16: getstatic #3 // Field MyOtherBigClass.VAR_2:I
19: istore_3
20: return
Bytecode using the ternary:
public static void main(java.lang.String[]);
Code:
0: iconst_0
1: istore_1
2: iconst_2
3: istore_2
4: iload_1
5: iload_2
6: if_icmple 15
9: getstatic #2 // Field MyBigClass.VAR_1:I
12: goto 18
15: getstatic #3 // Field MyOtherBigClass.VAR_2:I
18: istore_3
19: return
The resulting bytecode literally has just one extra instruction, which is storing the result in the first branch of the if-statement (wherease the ternary just stores the result at the end of the comparison). So, ternaries only execute the branch that would be followed according to the evaluation of the argument, just like an if-else statement.
And, because I was curious, I decided to check if a double ternary is equivalent to an if-elif-else. (Spoiler it is). I used this code to test it, same process as above:
public static void main(String[] args) {
int a = 0;
int b = 2;
int c = 3;
int d = a > b ? MyBigClass.VAR_1 : a > c ? MyOtherBigClass.VAR_2 : 0;
// int d;
// if (a > b) {
// d = MyBigClass.VAR_1;
// } else if (a > c) {
// d = MyOtherBigClass.VAR_2;
// } else {
// d = 0;
// }
}
The bytecode generated for if-elif-else:
public static void main(java.lang.String[]);
Code:
0: iconst_0
1: istore_1
2: iconst_2
3: istore_2
4: iconst_3
5: istore_3
6: iload_1
7: iload_2
8: if_icmple 19
11: getstatic #2 // Field MyBigClass.VAR_1:I
14: istore 4
16: goto 35
19: iload_1
20: iload_3
21: if_icmple 32
24: getstatic #3 // Field MyOtherBigClass.VAR_2:I
27: istore 4
29: goto 35
32: iconst_0
33: istore 4
35: return
The bytecode generated for ternary:
public static void main(java.lang.String[]);
Code:
0: iconst_0
1: istore_1
2: iconst_2
3: istore_2
4: iconst_3
5: istore_3
6: iload_1
7: iload_2
8: if_icmple 17
11: getstatic #2 // Field MyBigClass.VAR_1:I
14: goto 29
17: iload_1
18: iload_3
19: if_icmple 28
22: getstatic #3 // Field MyOtherBigClass.VAR_2:I
25: goto 29
28: iconst_0
29: istore 4
31: return
What Javac Source Code Actually Does
For the bold the brave and the few
I decided to look at the source for javac... It took awhile, but with a little help from their hitchhiker's guide to javac, I was able to find the one line that definitively determines what happens. Check it out (Line 914): https://hg.openjdk.java.net/jdk9/jdk9/langtools/file/65bfdabaab9c/src/jdk.compiler/share/classes/com/sun/tools/javac/parser/JavacParser.java
Do you see that? Let me clarify this a bit, lines 905-918 say this:
/** Expression1Rest = ["?" Expression ":" Expression1]
*/
JCExpression term1Rest(JCExpression t) {
if (token.kind == QUES) {
int pos = token.pos;
nextToken();
JCExpression t1 = term();
accept(COLON);
JCExpression t2 = term1();
return F.at(pos).Conditional(t, t1, t2);
} else {
return t;
}
}
The comment tells us this is what they use for parsing ternary expressions, and if we look at what it returns, it returns a conditional where t
is the expression being evaluated, t1
is the first branch, and t2
is the second branch. Let's take a look at Conditional
just to be sure. It looks like Conditional
is being called from F
, which if we dig a little deeper we can find out is the TreeMaker
, what is a tree maker you may ask? Well, it's specifically an Abstract Syntax Tree which is often used as an intermediate representation of the code being parsed (check it out here https://en.wikipedia.org/wiki/Abstract_syntax_tree). Anyways, if we look inside that file (https://hg.openjdk.java.net/jdk9/jdk9/langtools/file/65bfdabaab9c/src/jdk.compiler/share/classes/com/sun/tools/javac/tree/TreeMaker.java) we can see at lines 306-313 this:
public JCConditional Conditional(JCExpression cond,
JCExpression thenpart,
JCExpression elsepart)
{
JCConditional tree = new JCConditional(cond, thenpart, elsepart);
tree.pos = pos;
return tree;
}
Which further confirms exactly what we thought, that a ternary expression is compiled exactly the same as an if-else statement (otherwise known as a conditional statement) :) I encourage anyone interested to take a look at the hitchhiker's guide (https://openjdk.java.net/groups/compiler/doc/hhgtjavac/index.html) and the code, it's actually really interesting to see how even a commercial grade compiler follows a lot of the principle things that you learn about in your standard compiler course at college.