31

Asked an unrelated question where I had code like this:

public boolean equals(Object obj)
{
    if (this == obj)
        return true;

    if (obj == null)
        return false;

    if (getClass() != obj.getClass())
        return false;

    // Check property values
}

I got a comment which claimed that this was not optimal, and that it instead (if I understood correctly) should do this:

public boolean equals(Object obj)
{
    if (this == obj)
        return true;

    else if (obj == null)
        return false;

    else if (getClass() != obj.getClass())
        return false;

    // Check property values
}

Because of the return statements, I can't really see why any of them should be more efficient or faster than the other. Given a certain object, both methods would have to do an equal number of checks as far as I can see. And because of the return statements, no extra code would run in any of them.

Am I missing something here? Is there something to it? Are there some compiler optimizations or something going on or whatever?

I know this is micro optimization and I will most likely stick with the first either way, since I think it looks cleaner with all the ifs on the same position. But I can't help it; I'm curious!

Community
  • 1
  • 1
Svish
  • 152,914
  • 173
  • 462
  • 620
  • 14
    Tell me the name of the guy who made that comment and I'll downvote him for that ;) – Andreas Dolk Apr 14 '11 at 12:50
  • 3
    I would advise not to bother about such micro level optimizations. You can always find purists who split hair well. Such optimations are well handled by compiler and chances are the first one already gets reduced to second version (or vice versa depending on what your compiler thinks is good). – d-live Apr 14 '11 at 12:52
  • 1
    @Jigar Joshi - a virtual (+1) instead for raising your hand :-) – Andreas Dolk Apr 14 '11 at 12:59
  • Jigar's post was utterly stupid. I know we are supposed to be polite and all, but c'mon. No wonder the quality of work in software is in shambles. This is crap people should learn in their first introductory programming course. To not know that an else is simply syntactic sugar for another if (which is ultimately just another jump/goto under the hood), that's not acceptable from anybody that has passed his/her introductory programming courses. There are a lot of things in programming/CS that are very complicated. This ain't one of them. – luis.espinal Apr 14 '11 at 13:08
  • What I was thinking is [this](http://ideone.com/GMBCE) It was totally out of aspect, @Andreas_D @Swish Thanks :) – jmj Apr 14 '11 at 13:31
  • @Jigar, Just to clearify, this wasn't to bash you in any way! Was just genuinely curious :) – Svish Apr 14 '11 at 14:11
  • **Tautology** the saying of the same thing twice in different words, generally considered to be a fault of style – MaxZoom Nov 13 '15 at 15:07

5 Answers5

25

The generated byte code is identical for those two cases, so it's purely a matter of style.

I produced two methods e1 and e2 and both produced this byte code (read using javap -v):

public boolean e1(java.lang.Object);
  Code:
   Stack=2, Locals=2, Args_size=2
   0:   aload_0
   1:   aload_1
   2:   if_acmpne   7
   5:   iconst_1
   6:   ireturn
   7:   aload_1
   8:   ifnonnull   13
   11:  iconst_0
   12:  ireturn
   13:  aload_0
   14:  invokevirtual   #25; //Method java/lang/Object.getClass:()Ljava/lang/Class;
   17:  aload_1
   18:  invokevirtual   #25; //Method java/lang/Object.getClass:()Ljava/lang/Class;
   21:  if_acmpeq   26
   24:  iconst_0
   25:  ireturn

I left out the code I put after that to make it compile.

Joachim Sauer
  • 302,674
  • 57
  • 556
  • 614
  • 3
    @Jigar: There is no smartness necessary here, the compiler had no real choice than to generate the same code for all cases. There is no `else` statement in byte code, only a bunch of `if-condition-goto` ones. – Paŭlo Ebermann Apr 14 '11 at 13:01
  • 1
    The only smartness necessary is that the compiler needs to know that after a `ireturn` it need not put a `jump-to-the-end-of-the-if-else-cascade` statement. And that's fairly trivial to check. – Joachim Sauer Apr 14 '11 at 13:02
  • 3
    @Jigar - *"Interesting, Compiler is very smart.*" You think? Newsflash for you Jigar. All compilers have been doing this since the beginning of time, since 3rd generation programming languages were invented (and even since people started using macro instructions in assembly). Welcome to compiler technology invented almost 60 years ago. You don't even need to know compiler technology. Simple logic dictates these two sets of if (and if-else) statements **are** equivalent. – luis.espinal Apr 14 '11 at 13:13
  • 4
    @luis: your statement is factually true, but I don't see a reason for the tone you're using. Not everyone studied compiler techniques. – Joachim Sauer Apr 14 '11 at 13:27
  • @Paŭlo Ebermann , @Joachim Sauer What I was thinking is [this](http://ideone.com/GMBCE) It was totally out of aspect, @Andreas_D @Swish Thanks :) , deleted the comment intentionally. – jmj Apr 14 '11 at 13:31
  • I would recommend compiler construction? What we're establishing in these comments are that some are just certified while others are university graduates. Now, only if companies could see the difference and pay the university smarta$$es better....lol – Buhake Sindi Apr 14 '11 at 13:37
  • @Joachim - you don't learn that from taking a class on compiler techniques. You learn that from basic programming courses as we learn the semantic equivalence of control structures. We learn it when we peek at assembly. Sadly the later is not being taught that much anymore, but the former is learned from basic/fundamental programming and the history of programming languages (which is also covered in every single bloody college textbook on programming/CS/MIS.) The tone is justifiable, and not, this is not specific to compiler construction. It is not an obscure, esoteric advanced topic. – luis.espinal Apr 14 '11 at 14:03
  • @luis: just because the two forms are obviously identical, does **not** imply that the compiler produces identical code. – Joachim Sauer Apr 14 '11 at 14:05
  • @Joachim - in most modern compilers, it does, been for a long time. And even if we ignore the issue of compilers and we assume the unlikely (that a compiler will produce significantly different output), this is one of the things that **should (read must)** be obvious, that these two set of if (and if-else) blocks are semantically equivalent. – luis.espinal Apr 14 '11 at 16:13
11

Neither one is more efficient than the other. The compiler can easily see that the two are identical, and in fact Suns/Oracles javac produces identical bytecode for the two methods.

Here is an IfTest class:

class IfTest {

    public boolean eq1(Object obj) {
        if (this == obj)
            return true;

        if (obj == null)
            return false;

        if (getClass() != obj.getClass())
            return false;

        return true;
    }


    public boolean eq2(Object obj) {

        if (this == obj)
            return true;

        else if (obj == null)
            return false;

        else if (getClass() != obj.getClass())
            return false;

        return true;
    }
}

I compiled it with javac and the disassembly is as follows:

public boolean eq1(java.lang.Object);
  Code:
   0:   aload_0
   1:   aload_1
   2:   if_acmpne   7
   5:   iconst_1
   6:   ireturn
   7:   aload_1
   8:   ifnonnull   13
   11:  iconst_0
   12:  ireturn
   13:  aload_0
   14:  invokevirtual   #2; //Method Object.getClass:()Ljava/lang/Class;
   17:  aload_1
   18:  invokevirtual   #2; //Method Object.getClass:()Ljava/lang/Class;
   21:  if_acmpeq   26
   24:  iconst_0
   25:  ireturn
   26:  iconst_1
   27:  ireturn

 

public boolean eq2(java.lang.Object);
  Code:
   0:   aload_0
   1:   aload_1
   2:   if_acmpne   7
   5:   iconst_1
   6:   ireturn
   7:   aload_1
   8:   ifnonnull   13
   11:  iconst_0
   12:  ireturn
   13:  aload_0
   14:  invokevirtual   #2; //Method Object.getClass:()Ljava/lang/Class;
   17:  aload_1
   18:  invokevirtual   #2; //Method Object.getClass:()Ljava/lang/Class;
   21:  if_acmpeq   26
   24:  iconst_0
   25:  ireturn
   26:  iconst_1
   27:  ireturn

That is, I would recommend using the first version (without the else). Some people may argue that it's cleaner with the else parts, but I would argue the opposite. Including the else indicates that the programmer didn't realize that it was unnecessary.

aioobe
  • 413,195
  • 112
  • 811
  • 826
  • +1 for the analysis, I already pointed this out in a comment above to the question. If you try out the single return version as well i believe it would again end up exactly the same - the compiler wont bother about the hassle of creating a variable and doing mem operations when it knows all it is there for is to return results. – d-live Apr 14 '11 at 13:02
  • Interesting that your compiler has a len of 27 and the compiler of @Joachim Sauer has 25. Which JDK did you use? – rajah9 Apr 14 '11 at 14:05
  • I agree, including the else indicates the programmer didn't realize it was unnecessary. – Christopher Perry May 27 '11 at 23:08
5

I don't see any practical reason to replace one of those implementations with the other one - in any direction.

The second example would make sense if you wanted to avoid multiple return statements in one method - some people prefer that way of coding. Then we need the if-else if constructs:

public boolean equals(Object obj)
{
    boolean result = true;

    if (this == obj)
        result = true;

    else if (obj == null)
        result = false;

    else if (getClass() != obj.getClass())
        result = false;

    return result;
}
Andreas Dolk
  • 113,398
  • 19
  • 180
  • 268
3

Think of it this way. When a return statement is executed, control leaves the method, so the else doesn't really add any value, unless you want to argue that it adds readability (which I don't really think it does, but others may disagree).

So when you have:

if (someCondition)
    return 42;

if (anotherCondition)
    return 43;

There's not really any value in adding an else to the second if.

In fact, I use a tool when writing C# code called Resharper, and it will actually mark the else as useless code in these situations. So I think that generally, it's better to leave them out. And as Joachim already mentioned, the compiler optimizes them away anyway.

dcp
  • 54,410
  • 22
  • 144
  • 164
  • 2
    I totally agree with Resharper there... When I see such elses, I tend to remove them. Similarly, I cringe when I see if (cond) return true; else return false; ... – PhiLho Apr 14 '11 at 13:08
0

I think this code can be improved a little (mind you, it is very readable):

  if (obj == null)
        return false;

  if (getClass() != obj.getClass())
        return false;

The instanceof operator is equivalent to both of those combined and is probably faster - less code, and no method invocations:

  if (!(obj instanceof MyClass))
        return false;

But what do I know.... I'm too lazy to analyze the byte code (having never done it before). :-p

Julius Musseau
  • 4,037
  • 23
  • 27
  • 1
    You should be aware of that `getClass()` and `instanceof` are *not* equivalent. If you have two classes `A` and `B` where `B extends A`, then `getClass()` is always `false`, whereas `b instanceof A` is `true`. – beatngu13 Oct 26 '16 at 07:29