【问题标题】:Is there any appreciable difference between if and if-else?if 和 if-else 之间有什么明显的区别吗?
【发布时间】:2010-04-20 19:00:35
【问题描述】:

给定以下代码sn-ps,有什么明显的区别吗?

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

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

【问题讨论】:

  • °&$§ 是如何发明的?*!单退出原则?真的,它使代码更具可读性吗?
  • 很多人(包括我)会说是的,确实如此。
  • this 的情况下,#1 和 #2 的功能相同(else 是多余的)。但是,如果表达式都为真(即:input>50==(input%2)),那将是一个完全不同的故事。考虑您正在测试的条件的域,以及它在未来更新中可能会发生的变化。至于 single exit principal,我已经看到它使某些代码变得更加其他代码的可读性大大降低,因此将其视为工具而不是诫命。

标签: java coding-style maintainability


【解决方案1】:

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

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

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

【讨论】:

    【解决方案2】:

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

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

    【讨论】:

      【解决方案3】:
      • 在第一个:

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

      • 第二个肯定更好,不仅可以防止这种情况发生,而且有助于明确说明,thisthis other没有了。

        如果我们在 if 中编写的所有代码最多 10 行,这并不重要,但不幸的是,情况并非如此,存在其他程序员出于某种原因认为 if 正文应该是> 200 行长……无论如何。

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

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

      【讨论】:

        【解决方案4】:

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

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

        doStuffdoOtherStuff 都会返回 true。

        【讨论】:

          【解决方案5】:

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

          【讨论】:

            【解决方案6】:

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

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

            【讨论】:

              【解决方案7】:

              当两个例子不相似时,想想这种情况:

                  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 应用程序来说,考虑到的差异很小:)。

              【讨论】:

                【解决方案8】:

                在你的情况下,第二个 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.");
                }
                

                【讨论】:

                  【解决方案9】:

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

                  【讨论】:

                  • 你几乎肯定是不正确的 - 任何现代编译器都会将这些中的每一个优化为相同的代码。无论如何,“将控制权交还给程序”不需要处理能力或内存
                  • 也许你误会了。我的意思是,如果第一个条件验证为真,就会发生处理能力的浪费。在他的前两个示例中,控制流将返回给调用方法,而不是继续进行毫无意义的验证。如果我错了,请纠正我,但是说执行额外的不必要的代码“不需要处理能力”是不正确的,不是吗?
                  • 不。在语义上遵循您的句子,'第三个sn-p效率很低。因为你等待返回......直到最后一行代码......你浪费了处理能力'。您只批评了第三个 sn-p,因为您已经驳回了 1 和 2。我的主张成立。
                  • 重读我的答案后,由于我的语义,您是对的。我没有彻底解释为什么我最初认为 sn-p 3 会浪费处理时间/功率。在重读 OP 之后,我也意识到,由于代码的“else”部分,我将要提出的关于 sn-p 3 的观点将没有实际意义。无论如何,我至少在重读 OP 时注意到了“toBeReturned”变量。该变量(除了帮助我节省面子之外)会产生更多开销(占用更多内存),从而使其效率低下。因此,对于 OP,如果可以避免,请不要编写像 sn-p 3 这样的代码块。 :)
                  猜你喜欢
                  • 1970-01-01
                  • 1970-01-01
                  • 1970-01-01
                  • 1970-01-01
                  • 1970-01-01
                  • 1970-01-01
                  • 2014-07-22
                  • 1970-01-01
                  • 2021-11-28
                  相关资源
                  最近更新 更多