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
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.
ReplyDeleteIn 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.
The compiler should resolve to the same code internally so there is no difference.
ReplyDeletetry 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.
ReplyDeleteOK, a more complete answer:
ReplyDeleteI 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.
The JLS says that
ReplyDeletethe 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.
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.
ReplyDeleteThinking about micro-optimizations is in almost any cases a waste of time and leads to thinking in wrong ways...
ReplyDeleteI asked a similar question regarding C++ / VS2008.
ReplyDeletehttp://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.