views:

141

answers:

5

Hello,

Does the Java Compiler optimize a statement like this

if (a == true) {
 if (b == true) {
  if (c == true) {
   if(d == true) {
       //code to process stands here
   }
  }
 }
}

to

if (a == true && b==true && c==true && d == true)

So that's my first question: Do both take exactly the same "CPU Cycles" or is the first variant "slower".

My Second question is, is the first variant with the cascaded if considered bad programming style as it is so verbose?

(I like the first variant as I can better logically group my expressions and better comment them (my if statements are more complex than in the example), but maybe that's bad programming style?) and even slower, that's why I am asking...

Thanks Jens

+15  A: 

Firsly DONT USE a == TRUE:

 if (a) { ... }

Secondly such code:

public class Test {
  public int f(boolean a, boolean b, boolean c, boolean d) {
    if (a && b && c && d) {
      return 1;
    } else {
      return 2;
    }
  }

  public int g(boolean a, boolean b, boolean c, boolean d) {
    if (a)
      if (b)
        if (c)
          if (d)
            return 1;
    return 2;
  }
}

is compiled into(javap -c Test):

public class Test extends java.lang.Object{
public Test();
  Code:
   0:   aload_0
   1:   invokespecial   #1; //Method java/lang/Object."<init>":()V
   4:   return

public int f(boolean, boolean, boolean, boolean);
  Code:
   0:   iload_1
   1:   ifeq    19
   4:   iload_2
   5:   ifeq    19
   8:   iload_3
   9:   ifeq    19
   12:  iload   4
   14:  ifeq    19
   17:  iconst_1
   18:  ireturn
   19:  iconst_2
   20:  ireturn

public int g(boolean, boolean, boolean, boolean);
  Code:
   0:   iload_1
   1:   ifeq    19
   4:   iload_2
   5:   ifeq    19
   8:   iload_3
   9:   ifeq    19
   12:  iload   4
   14:  ifeq    19
   17:  iconst_1
   18:  ireturn
   19:  iconst_2
   20:  ireturn

}

As you can see the bytecode is identical.

Thirdly - it depends on problem but usually it is too verbose. If you comment to such details:

  • Your comments are way too verbose. Thay should support code not duplicate it (BAD: x = x + 1; // Increase x by 1) - possibly assembler is only exception as add rax, 1 ; Increase x by 1 informs that rax is x.
  • Your code is doing really 'smart' things that it probably shouldn't (however some case are justified)
Maciej Piechotka
I'm not sure if I agree with "don't use x==true". My experience is that it is more readable when skimming code than the distinction between identifier and !identifier.
Uri
probably there shouldn't be x. Read `if (finished) System.exit(0)`. Loudly in English "If finished exit". Read `if (finished == true) System.exit(0)`. "If finished is true exit". Usually you use 1. long descriptive names and 2. booleans only in conditions.
Maciej Piechotka
@MP A perfect answer. The only thing I would add is that one can often use polymorphism to replace long lists of conditions, which will make the whole thing easier to test.
CurtainDog
@CD "A perfect answer." -> Not quite. Even if bytecode was not identical the JIT could optimize it anyway to same instructions - I forgot to mention it. However as it is identical it must be optimized to same instructions.
Maciej Piechotka
I completely agree with not using if (a==true)
Steve Kuo
+3  A: 

The Java "compiler" will likely not do any optimization here (compile both, and decompile them to compare). But the JVM runtime might very well do so.

However, that said, this is a micro-optimization; code so that your code is the most understandable by the next developer to come along.

The best practice here is the most readable code.

And, of course, don't use (xxx == true), which is horrible a practice, use (xxx) instead.

Software Monkey
It's not an optimization.
EJP
+1  A: 

According to document, && and || operators exhibit "short-circuiting" behavior, and only evaluated if needed, so should be same CPU cycles for both way.

The && and || operators perform Conditional-AND and Conditional-OR operations on two boolean expressions. These operators exhibit "short-circuiting" behavior, which means that the second operand is evaluated only if needed.

For more info, See

S.Mark
+1  A: 

The first variant makes it easier to place a break point on one or your conditions, and stack traces for any exceptions thrown while checking your conditions will also indicate which line was being checked.

Stephen Denne
IMHO if the coditions mutates state (especially not in separate functions)[1] it is some sign of beeing "too smart". So either they are exported to other functions and you can break on them or you can break just after condition in each branch (or press next) and check the results.[1] Possibly the exception is checking for non-error failure.
Maciej Piechotka
A: 

It's not an optimization. The two versions are completely equivalent. Neither runs faster.

EJP