Monday, May 7, 2012

What is the performance difference, if any, between if(!foo) and if(foo == false) in Java?


Logically, if(!foo) and if(foo == false) are equivalent. How are they represented in Java? Is there any difference between the two after compilation, either in the bytecode or in performance? I was unable to find an answer in the JLS, and searching brought up a lot of results about = vs. == typos and ==/equals() behavior. (In this case, the symbols hampered my searching; for future searchers, negation operator, equals false, equal to false, not condition).



To head off the CW debate: this question is NOT asking which variant people prefer or which is considered better style. I am interested in the differences in the implementation of the language, so there is a correct answer. Related-but-not-quite-a-dupe: Difference between while (x = false) and while (!x) in Java?



EDIT:



The general consensus seems to be that a good compiler should optimize these to the same thing. That makes sense and is what I suspected, but -- to ask an even MORE academic question -- is that behavior actually mandated anywhere, or is it "merely" the reasonable thing to do?


Source: Tips4all

8 comments:

  1. The JLS would specify the required behavior of the statements. However, how they are implemented is an implementation detail of the compiler and the JVM.

    In practice, any compiler worth its salt should emit the same bytecode for those statements. And even if not, the JVM would optimize them properly.

    Also, a better way to answer this, is to check for yourself, using javap:


    Compile a Test.java with the following content:

    class Test {
    void equals(boolean f) {
    if (f == false) {}
    }
    void not(boolean f) {
    if (!f) {}
    }
    }
    $ javac Test.java

    De-assemble it:

    $ javap -c Test
    Compiled from "Test.java"
    class Test extends java.lang.Object{
    Test();
    Code:
    0: aload_0
    1: invokespecial #1; //Method java/lang/Object."<init>":()V
    4: return


    void equals(boolean);
    Code:
    0: iload_1
    1: ifne 4
    4: return


    void not(boolean);
    Code:
    0: iload_1
    1: ifne 4
    4: return


    }



    UPDATE:
    Responding your question about the "academic" question. As mentioned above, the JLS is only concerned with the behavior. There is nothing in the standard that actually specifies how it should be implemented (well, JVMS provides a lot of guidance).

    As long as the compiler preserves the same identical behavior, the compiler is free to implement it different, with possibility different runtime performance.

    ReplyDelete
  2. The compiler should resolve to the same code internally so there is no difference.

    ReplyDelete
  3. try decompiling the byte code and see how different the code looks. I would guess the compile would resolve them almost identically and any slight difference would result in negligible performance difference.

    ReplyDelete
  4. OK, a more complete answer:

    I would be very surprised if any compiler generated different bytecode for these variations. For anyone who's interested, it should be easy enough to check using a disassembler.

    Given that both expressions (most probably) compile to the same bytecode, I expect no difference in size or performance.

    ReplyDelete
  5. The JLS says that


    the expression in
    an if block is evaluated, then the
    result of that expression is compared to
    true


    In both the not case and the compare object cases, an expresion needs to be evaluated and then compared to true. If you were checking a value rather than performaing an operator on it, there may be a theoretical performance benefit as the expression evaluation becomes a no op.

    But in this case, I'd expect the JIT to produce the same bytecode for both expressions.

    ReplyDelete
  6. There should be no difference in the bytecode generated for those two results and if it did unless you are creating code for a device with very limited resources (in which case you should not be writing in Java) than the difference would be negligible and you should decide which of the two ways of writing this code is a more obvious solution.

    ReplyDelete
  7. Thinking about micro-optimizations is in almost any cases a waste of time and leads to thinking in wrong ways...

    ReplyDelete
  8. I asked a similar question regarding C++ / VS2008.

    http://stackoverflow.com/questions/1911572/would-vs2008-c-compiler-optimize-the-following-if-statement

    To avoid = vs == typos in C++, you would tend to write

    if (NULL == ptr) { ... }
    if (false == boo) { ... }
    if (20 == num) { ... }


    etc.

    This is slightly less readable until you get used to it.

    ReplyDelete