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

  显示原文与译文双语对照的内容

问一个无关的问题我在哪里拥有这样的代码:


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
}

因为返回语句,我不能真正看出为什么它们中的任何一个比另一个更高效或者更快。 给定一个特定的对象,这两种方法都必须做同样数量的检查,我可以看到。 由于返回语句,任何额外的代码都不会在其中运行。

我在这里漏掉了什么? 这里面有什么东西? 是否有编译器优化或者其他的问题?

我知道这是微优化,我最喜欢的是第一和方法,因为我认为它在同一位置上看起来很干净。 但是我无能为力;我很好奇 !

时间: 原作者:

生成的字节代码对于这两种情况是相同的,所以它纯粹是一种风格。

我生成了两种方法 e1e2,同时生成了这个字节代码( 使用 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

我忘记了我放在后面的代码来编译。

原作者:

一个比另一个更高效。 编译器可以很容易地看到,这两个是相同的,事实上太阳/神谕 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

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

原作者:

我没有看到任何实际的理由,用其他的方法替换其中一个实现。

如果你想避免多个返回语句,第二个例子就有意义了- 有些人喜欢这种编码方式。 我们需要if-else如果结构:


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;
}

原作者:

以这种方式思考。 当执行return语句时,控件会离开该方法,因此 else 不会真正添加任何值,除非你想争辩它增加了可读性( 我觉得它并不真实,但其他人可能不同意) 。

所以当你拥有:


if (someCondition)
 return 42;

if (anotherCondition)
 return 43;

else 添加到第二个 if 时没有任何值。

事实上,我在编写 C# 代码的时候使用了一个工具,叫做 Resharper,它实际上将 else 标记为在这些情况下无用的代码。 所以我认为总的来说,最好把它们去掉。 就像Joachim已经提到的那样,编译器会优化它们。

我认为这个代码可以改进一些( 请注意,这是非常可读性):


 if (obj == null)
 return false;

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

instanceof 运算符等价于两个组合,并且可能更快- 代码少,没有方法调用:


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

但我怎么知道。 我懒得分析字节代码( 从未完成过) 。 :-p

...