I wrote this simple Test
class to see how Java evaluates boolean
algebra at the Bytecode level:
public class Test {
private static boolean a, b;
public static boolean method1(){
return !(a || b);
}
public static boolean method2(){
return !a && !b;
}
}
If you simplify method1()
using DeMorgan's Laws, you should get method2()
. After looking at the Bytecode (using javap -c Test.class), it looks like:
Compiled from "Test.java"
public class Test {
public Test();
Code:
0: aload_0
1: invokespecial #1 // Method java/lang/Object."<init>":
()V
4: return
public static boolean method1();
Code:
0: getstatic #2 // Field a:Z
3: ifne 16
6: getstatic #3 // Field b:Z
9: ifne 16
12: iconst_1
13: goto 17
16: iconst_0
17: ireturn
public static boolean method2();
Code:
0: getstatic #2 // Field a:Z
3: ifne 16
6: getstatic #3 // Field b:Z
9: ifne 16
12: iconst_1
13: goto 17
16: iconst_0
17: ireturn
}
So my question is, why is method1()
and method2()
exactly the same at the Bytecode level?
What your seeing is a compiler optimization. When javac
encounters method1()
it applies an optimization (based on De Morgan's Laws as you pointed out but also short circuiting the &&
comparison) that allows it to branch early if a
is true
(thus no need to evaluate b
).