Java:if-return-if-return 与 if-return-elseif-return

发布于 2024-11-01 10:48:19 字数 868 浏览 0 评论 0原文

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

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
}

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

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

我知道这是微观优化,我很可能会坚持使用第一种方式,因为我认为所有 if 都位于同一位置时它看起来更干净。但我无能为力;我很好奇!

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!

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(5

温暖的光 2024-11-08 10:48:19

这两种情况生成的字节码是相同的,因此这纯粹是风格问题。

我生成了两个方法 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

我遗漏了后面放置的代码使其编译。

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.

空宴 2024-11-08 10:48:19

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

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

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.

这个俗人 2024-11-08 10:48:19

我认为没有任何实际理由将其中一种实现替换为另一种实现 - 在任何方向上。

如果您想避免在一个方法中使用多个 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;
}

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;
}
那一片橙海, 2024-11-08 10:48:19

这样想吧。当执行 return 语句时,控制权离开方法,因此 else 并不会真正添加任何值,除非您想争辩说它增加了可读性(我真的不认为它会这样做,但其他人可能不同意)。

因此,当您遇到以下情况时:

if (someCondition)
    return 42;

if (anotherCondition)
    return 43;

else 添加到第二个 if 中实际上没有任何价值。

事实上,我在编写 C# 代码时使用了一个名为 Resharper 的工具,它实际上会标记 else 在这些情况下是无用的代码。所以我认为一般来说,最好将它们排除在外。正如 Joachim 已经提到的,编译器无论如何都会优化它们。

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.

吾性傲以野 2024-11-08 10:48:19

我认为这段代码可以稍微改进一下(请注意,它非常可读):

  if (obj == null)
        return false;

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

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

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

但是我知道什么......我懒得分析字节码(以前从未这样做过)。 :-p

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

~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文