Java:if-return-if-return vs if-return-elseif-return

Svi*_*ish 27 java if-statement micro-optimization

问一个无关的问题,我有这样的代码:

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

    if (obj == null)
        return false;

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

    // Check property values
}
Run Code Online (Sandbox Code Playgroud)

我得到了一条评论,声称这不是最优的,相反(如果我理解正确的话)应该这样做:

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
}
Run Code Online (Sandbox Code Playgroud)

由于返回语句,我无法真正理解为什么它们中的任何一个应该比另一个更高效或更快.鉴于某个对象,就我所见,这两种方法都必须进行相同数量的检查.并且由于返回语句,不会在其中任何一个中运行额外的代码.

我在这里错过了什么吗?有东西吗?是否有一些编译器优化或正在发生的事情或其他什么?

我知道这是微优化,我很可能会坚持第一种方式,因为我认为它看起来比较清晰,所有的ifs都在同一个位置上.但我无能为力; 我很好奇!

Joa*_*uer 23

对于这两种情况,生成的字节代码是相同的,因此它纯粹是一种风格问题.

我生成了两个方法e1,e2并且都生成了这个字节代码(使用读取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

我省略了我之后编写的代码以使其编译.

  • @Jigar:这里没有必要的智能,编译器没有真正的选择而不是为所有情况生成相同的代码.字节代码中没有`else`语句,只有一堆`if-condition-goto`语句. (3认同)
  • @luis:你的陈述事实上是正确的,但我没有看到你使用的语气的原因.不是每个人都学习编译技术 (3认同)
  • @Jigar - *"有趣,编译器很聪明.*"你觉得呢?给你的快报Jigar.自从第一代编程语言被发明以来,所有编译器都从一开始就这样做了(甚至自从人们开始在汇编中使用宏指令以来).欢迎使用近60年前发明的编译器技术.您甚至不需要了解编译器技术.简单的逻辑规定这两组if(和if-else)语句**是**等价的. (2认同)

aio*_*obe 9

两者都没有比另一个更有效率.编译器可以很容易地看到两者是相同的,实际上Suns/Oracles 为这两种方法javac生成相同的字节码.

这是一IfTest堂课:

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;
    }
}
Run Code Online (Sandbox Code Playgroud)

我编译了它,javac反汇编如下:

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
Run Code Online (Sandbox Code Playgroud)

 

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
Run Code Online (Sandbox Code Playgroud)

也就是说,我建议使用第一个版本(没有else).有些人可能认为它其他部分相比更干净,但我认为相反.包括else表明程序员并没有意识到,这是不必要的.


And*_*s_D 5

我认为没有任何实际理由可以用任何方向替换其中一个实现.

如果你想在一种方法中避免多个return语句,那么第二个例子就有意义了 - 有些人更喜欢这种编码方式.然后我们需要if-else if构造:

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;
}
Run Code Online (Sandbox Code Playgroud)