8

鉴于以下代码片段,有什么明显的区别吗?

public boolean foo(int input) {
   if(input > 10) {
       doStuff();
       return true;
   }
   if(input == 0) {
       doOtherStuff();
       return true;
   }

   return false;
}

对比

public boolean foo(int input) {
   if(input > 10) {
      doStuff();
      return true;
   } else if(input == 0) {
      doOtherStuff();
      return true;
   } else {
      return false;
   }
}

或者使用这段代码,单退出原则会更好吗?

public boolean foo(int input) {
   boolean toBeReturned = false;
   if(input > 10) {
      doStuff();
      toBeReturned = true;
   } else if(input == 0) {
      doOtherStuff();
      toBeReturned = true;
   }

   return toBeReturned;
}

有任何可察觉的性能差异吗?你觉得其中一个比其他的更易于维护/可读吗?

4

9 回答 9

9

在第二个示例中,您非常清楚地表明这两个条件是互斥的。
对于第一个,它不是很清楚,并且在(不太可能)input在两个 if 之间添加分配的情况下,逻辑会改变。
假设将来有人在input = 0第二个 if 之前添加。
当然这不太可能发生,但是如果我们在这里谈论可维护性,if-else 清楚地表明存在相互排斥的条件,而一堆 if 则没有,并且它们之间没有像 if 那样相互依赖- 其他块。

编辑:现在我看到了,在这个特定的例子中,return 子句强制互斥,但同样,我们谈论的是可维护性和可读性。

无论如何,关于性能,如果这是用 Java 编码的,你不应该关心几个 if 块的性能,如果它是在一个非常慢的硬件中嵌入 C,也许,但肯定不是用 java。

于 2010-04-20T19:06:47.083 回答
4

使用最能描述您意图的任何形式。

如果事情这么简单,请不要遵循单一退出原则——它只会让它变得更加混乱。

于 2010-04-20T19:03:55.057 回答
4
  • 在第一个:

    最终,由于某种奇怪的原因,当你不看的时候,有人会添加一些 add 语句,这会使这个方法在某些奇怪的条件下失败,每个人(或者最糟糕的是,一个人)将花费 4 小时。看了源代码,调试了应用程序,终于发现中间有东西。

  • 第二个肯定更好,它不仅可以防止这种情况,而且还有助于明确说明,不再是这个这个

    如果我们编写的所有代码if最多在 10 行之内,这实际上并不重要,但不幸的是,情况并非如此,存在其他程序员出于某种原因认为 if 主体应该 > 200 行长.. 。 反正。

  • 我不喜欢第三个,它强迫我寻找返回变量,并且更容易找到return关键字

关于速度性能,它们(几乎)相同。别担心。

于 2010-04-20T19:31:56.753 回答
1

在你的最后一个例子中,不要这样做:

public boolean foo(int input) {
   boolean toBeReturned = false;
   if(input > 10) {
      doStuff();
      toBeReturned = true;
   } else if(input == 0) {
      doOtherStuff();
      toBeReturned = true;
   }

   return toBeReturned;
}

但是这个(注意使用Java的final):

public boolean foo(int input) {
   final boolean toBeReturned;    // no init here
   if(input > 10) {
      doStuff();
      toBeReturned = true;
   } else if(input == 0) {
      doOtherStuff();
      toBeReturned = true;
   } else {
      toBeReturned = false;
   }
   return toBeReturned;
}

通过这样做,您可以明确您的意图,这对于支持“按意图编程”的 IDE 来说是天赐之物(即使在部分 AST 上,也无需“编译”即可查看潜在错误,一个好的 IDE 可以实际检查不完整的源代码——时间并给你即时警告)。

这样你一定不会忘记初始化你的返回值。如果稍后您决定毕竟您需要另一个条件,那就太好了。

自从我开始使用 IntelliJ IDEA(版本 4 左右,很久以前)以来,我一直都这样做,甚至更多,这为我节省了很多愚蠢的分心错误......

有些人会争辩说,对于这样一个简单的案例来说,代码太多了,但这完全没有抓住重点:重点是要明确意图,以便代码易于阅读并且以后可以轻松扩展,而不会意外忘记分配toBeReturned并且不会意外忘记从后面的子句返回,您可以添加。

否则,如果“简洁”是游戏的名称,那么我会写:

public boolean foo(int a) {
  return a > 10 ? doStuff() : a == 0 ? doOtherStuff() : false; 
}

doStuff和doOtherStuff都会返回 true。

于 2010-04-20T19:49:46.413 回答
0

语义上——不。性能方面,这取决于编译器,即它是否可以发现两个条件不能同时为真。我敢打赌标准的 Sun 编译器可以。是否使用单出口原则取决于口味。我个人讨厌它。

于 2010-04-20T19:05:42.810 回答
0

版本 #1 和 #2 可能比 #3 更快,但我认为性能差异很小。我宁愿专注于可读性

就个人而言,我永远不会使用版本 #2。在#1 和#3 之间,我会选择一个为所讨论的案例生成最易读的代码。我不喜欢我的方法中有很多退出点,因为它使代码难以分析。但是,有些情况下,当我们针对某些特殊情况立即退出时,流程会变得更加清晰,并继续处理主要情况。

于 2010-04-20T19:10:28.293 回答
0

当两个示例不相似时,请考虑这种情况:

    public boolean foo(int input) {
        if (input > 10) {
            // doStuff();
            return true;
        }
        System.out.println("do some other intermediary stuff");
        if (input == 0) {
            // doOtherStuff();
            return true;
        }

        return false;
    }

对比

    public boolean foo(int input) {
        if (input > 10) {
            // doStuff();
            return true;
        } 
        //System.out.println("doing some intermediary stuff... doesn't work");
        else if (input == 0) {
            // doOtherStuff();
            return true;
        } else {
            return false;
        }
        return false;
    }

第一种方法可能更灵活,但两种公式在不同的情况下都有其用途。

关于性能,我认为对于任何由理智的程序员编写的常规 Java 应用程序来说,考虑到的差异很小:)。

于 2010-04-20T19:12:23.493 回答
0

在你的情况下,第二个 if 只会在第一个 if 失败时被调用,所以它在这里不太重要,但是如果你的第一个 if 做了某事并且没有返回,那么第二个 if (这将永远是假的)仍然会被测试,除非它在一个 else-if 中。

换句话说,在某些情况下,if-else-if 和 if-if 之间的区别很重要,但这不是其中之一。

示例:试试这个,然后在删除 else 后尝试。你得到两个不同的输出:

int someNumber = 1;
if(someNumber < 5)
{
    someNumber += 5;
    Console.WriteLine("First call.");
}
else if(someNumber >= 5)
{
    Console.WriteLine("Second call.");
}
于 2010-04-20T19:13:19.263 回答
-1

在第一个和第二个片段之间,真的没有区别。然而,第三个片段效率很低。因为您等到方法中的最后一行代码才将程序的控制权返回给调用者,所以您浪费了处理能力/内存,而前两个代码片段在确定其中一个条件为真时立即返回控制权。

于 2010-04-20T19:05:46.590 回答