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

2022-09-01 10:48:30

问了一个不相关的问题,我有这样的代码:

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

    if (obj == null)
        return false;

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

    // Check property values
}

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

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
}

由于返回语句,我真的看不出为什么它们中的任何一个应该比另一个更高效或更快。给定某个对象,据我所知,这两种方法都必须执行相同数量的检查。由于返回语句,任何一个语句中都不会运行任何额外的代码。

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

我知道这是微优化,我很可能会坚持第一种方式,因为我认为在同一位置上的所有if看起来更干净。但我忍不住;我很好奇!


答案 1

对于这两种情况,生成的字节代码是相同的,因此这纯粹是样式问题。

我产生了两种方法,并且都产生了这个字节码(使用读取):e1e2javap -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

我省略了之后放入的代码,以使其编译。


答案 2

两者都不比另一个更有效。编译器可以很容易地看到两者是相同的,实际上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;
    }
}

我编译它,反汇编如下: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

 

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

也就是说,我建议使用第一个版本(没有)。有些人可能会争辩说,其他部分更干净,但我认为恰恰相反。包括程序员没有意识到这是不必要的迹象。elseelse


推荐