views:

456

answers:

8

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?

+11  A: 

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

Greg Smith
How about showing it the same way notnoop did.
Shaun F
How about not upvoting a free statement without any reference, proof, etc (even if true).
Pascal Thivent
"Show me the code."
Dave Jarvis
+35  A: 

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:

  1. 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
    
  2. 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.

notnoop
That's what I call good will! Congratulations for your patience!
Kico Lobo
`javap -c` disassembles, it doesn't decompile.
Pascal Thivent
Nice answer, thank you. Mentioning javap alone was enough for a +1, I'd never heard of it before.
Lord Torgamus
this is what you get when you use javap -verbose Test, javap -s Test only get the signature.
Agusti-N
Thanks... actually it's `-c`. `-verbose` would give you even more info (all the attributes)
notnoop
Great answer. Though I'm a bit surprised that the compiler emits a conditional at all given the empty code block and no side effects... I suppose the JIT ultimately kills that off.
mikera
A: 

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.

runrunraygun
or even take a look at the byte code itself http://stackoverflow.com/questions/800916/should-i-look-at-the-bytecode-that-is-produce-by-a-java-compiler
runrunraygun
A: 

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.

Carl Smotricz
A: 

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.

Robert Christie
A: 

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.

RHicke
A: 

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

Helper Method
See my comment in the question's thread.
Lord Torgamus
A: 

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.

Hamish Grubijan