Contrary to the answers of Pavel Horal,
Codo and yuvgin I argue that the compiler does NOT optimize away (or disregard) the ternary operator. (Clarification: I refer to the Java to Bytecode compiler, not the JIT)
See the test cases.
Class 1: Evaluate boolean expression, store it in a variable, and return that variable.
public static boolean testCompiler(final int a, final int b)
{
final boolean c = ...;
return c;
}
So, for different boolean expressions we inspect the bytecode:
1. Expression: a == b
Bytecode
0: iload_0
1: iload_1
2: if_icmpne 9
5: iconst_1
6: goto 10
9: iconst_0
10: istore_2
11: iload_2
12: ireturn
- Expression:
a == b ? true : false
Bytecode
0: iload_0
1: iload_1
2: if_icmpne 9
5: iconst_1
6: goto 10
9: iconst_0
10: istore_2
11: iload_2
12: ireturn
- Expression:
a == b ? false : true
Bytecode
0: iload_0
1: iload_1
2: if_icmpne 9
5: iconst_0
6: goto 10
9: iconst_1
10: istore_2
11: iload_2
12: ireturn
Cases (1) and (2) compile to exactly the same bytecode, not because the compiler optimizes away the ternary operator, but because it essentially needs to execute that trivial ternary operator every time. It needs to specify at bytecode level whether to return true or false. To verify that, look at case (3). It is exactly the same bytecode except lines 5 and 9 which are swapped.
What happens then and a == b ? true : false
when decompiled produces a == b
? It is the decompiler's choice that selects the easiest path.
Furthermore, based on the "Class 1" experiment, it is reasonable to assume that a == b ? true : false
is exactly the same as a == b
, in the way it is translated to bytecode. However this is not true. To test that we examine the following "Class 2", the only difference with the "Class 1" being that this doesn't store the boolean result in a variable but instead immediately returns it.
Class 2: Evaluate a boolean expression and return the result (without storing it in a variable)
public static boolean testCompiler(final int a, final int b)
{
return ...;
}
Bytecode:
0: iload_0
1: iload_1
2: if_icmpne 7
5: iconst_1
6: ireturn
7: iconst_0
8: ireturn
Bytecode
0: iload_0
1: iload_1
2: if_icmpne 9
5: iconst_1
6: goto 10
9: iconst_0
10: ireturn
Bytecode
0: iload_0
1: iload_1
2: if_icmpne 9
5: iconst_0
6: goto 10
9: iconst_1
10: ireturn
Here it is obvious that the a == b
and a == b ? true : false
expressions are compiled differently, as cases (1) and (2) produce different bytecodes (cases (2) and (3), as expected, have only their lines 5,9 swapped).
At first I found this surprising, as I was expecting all 3 cases to be the same (excluding the swapped lines 5,9 of case (3)). When the compiler encounters a == b
, it evaluates the expression and returns immediately after contrary to the encounter of a == b ? true : false
where it uses the goto
to go to line ireturn
. I understand that this is done to leave space for potential statements to be evaluated inside the 'true' case of the ternary operator: between the if_icmpne
check and the goto
line. Even if in this case it is just a boolean true
, the compiler handles it as it would in the general case where a more complex block would be present.
On the other hand, the "Class 1" experiment obscured that fact, as in the true
branch there was also istore
, iload
and not only ireturn
forcing a goto
command and resulting in exactly the same bytecode in cases (1) and (2).
As a note regarding the test environment, these bytecodes were produced with the latest Eclipse (4.10) which uses the respective ECJ compiler, different from the javac that IntelliJ IDEA uses.
However, reading the javac-produced bytecode in the other answers (which are using IntelliJ) I believe the same logic applies there too, at least for the "Class 1" experiment where the value was stored and not returned immediately.
Finally, as already pointed out in other answers (such as those by supercat and jcsahnwaldt) , both in this thread and in other questions of SO, the heavy optimizing is done by the JIT compiler and not from the java-->java-bytecode compiler, so these inspections while informative to the bytecode translation are not a good measure of how the final optimized code will execute.
Complement: jcsahnwaldt's answer compares javac's and ECJ's produced bytecode for similar cases
(As a disclaimer, I have not studied the Java compiling or disassembly that much to actually know what it does under the hood; my conclusions are mainly based on the results of the above experiments.)
if( foo == true )
"for readability"? – Incendiarismif ( isValid(input) ? true : false )
too. – Acclivityint x = y
reads naturally as "set the integer x to y," butbool z = x == y
reads like "set the boolean z to x equal to y," which sounds funny. – Bennirif (foo == false)
because they think!
is hard to spot in!foo
... – Pentheamif ( (isValid(input) ? true : false) == true )
– Dulcedulcea