【问题标题】:Why we use if, else if instead of multiple if block if the body is a return statement为什么我们使用 if,else if 而不是多个 if 块如果主体是返回语句
【发布时间】:2012-02-07 00:11:02
【问题描述】:

我一直习惯于使用 if、else-if 语句而不是多个 if 语句。

例子:

int val = -1;
if (a == b1) {
   return c1;
} else if (a == b2) {
   return c2;
} ...
...
} else {
   return c11;
}

与示例 2 相比如何:

if (a == b1) {
   return c1;
}
if (a == b2) {
   return c2;
}
....

if (a == b11) {
   return c11;
}

我知道在功能方面它们是相同的。但是最好的做法是做 if else-if 还是 not?当我指出他可以以不同的方式构建代码库以使其更清洁时,我的一位朋友提出了这个问题。这对我来说已经是很长时间的习惯了,但我从来没有问过为什么。

【问题讨论】:

  • 您指的是哪种语言? Java 还是 C++?
  • 它对我来说是 java,但我已经将它用于 c++ 和 Java 很长时间了......
  • 这是一个显着的区别,因为您可以在 C++ 中实现 operator== 来做讨厌的(副作用)事情(这也对优化产生影响......)。 AFAICR 这在 Java 中不起作用。
  • 由于比较不同的变量类型,有时使用 if-if-if 块语句很有效。就像在 JAVA 中一样,我正在检查名称、价格、金额是否都有值。由于 name 是 String 并且 price & amount 是 int,我将不得不做一个单独的 if 语句。这取决于您要处理的情况。

标签: java c++


【解决方案1】:

if-elseif-else 语句一旦找到正确的比较就会停止进行比较。 if-if-if 进行所有比较。第一个效率更高。

编辑: 在 cmets 中已经指出,您在每个 if 块内执行 return。在这些情况下,或者在控制权离开方法的情况下(异常),执行多个 if 语句和执行 if-elseif-else 语句之间没有区别。

不过,最好还是使用if-elseif-else。假设您更改了代码,使得您不在每个 if 块中执行 return。然后,为了保持效率,您还必须更改为 if-elseif-else 成语。从一开始就使用if-elseif-else 可以节省您在将来进行的编辑,并且对于阅读您的代码的人来说更清晰(通过略读您的代码来见证我刚刚给您的误解!)。

【讨论】:

  • 帖子暗示每个条件都做一个return,所以方法执行在一个条件成功后停止。
  • 等等。该示例在哪里不同意我的主张?
  • @LouisWasserman:我认为他是在回复我的帖子,而不是您的评论。我就是这么理解的,因为你们俩都指出了我帖子中的原始缺陷。
【解决方案2】:

b1 == b2的情况呢? (如果a == b1a == b2?)

发生这种情况时,一般来说,以下两段代码很可能会有不同的行为:

if (a == b1) {
   /* do stuff here, and break out of the test */
} 
else if (a == b2) {
   /* this block is never reached */
} 

和:

if (a == b1) {
   /* do stuff here */
}
if (a == b2) {
   /* do this stuff, as well */
}

如果您想清楚地描述不同情况下的功能,请使用if-elseswitch-case 进行一个测试

如果您想为多个案例提供不同的功能,请使用多个 if 块作为单独的测试

与其说是“最佳实践”问题,不如说是定义您是进行一项测试还是多项测试。

【讨论】:

    【解决方案3】:

    它们在功能上不等效。

    它在功能上等效的唯一方法是,如果您对 a 的每个可能值执行“if”语句(即:每个可能的 int 值,如 C 中的 limits.h 中定义的那样;使用 INT_MIN 和 INT_MAX,或Java 中的等价物)。

    else 语句允许您覆盖所有可能的剩余值,而无需编写数百万个“if”语句。

    此外,使用 if...else if...else 是更好的编码习惯,就像在 switch/case 语句中一样,如果您不提供“默认值”,您的编译器会警告您案例陈述。这可以防止您忽略程序中的无效值。例如:

    double square_root(double x) {
        if(x > 0.0f) {
            return sqrt(x);
        } else if(x == 0.0f) {
            return x;
        } else {
            printf("INVALID VALUE: x must be greater than zero");
            return 0.0f;
        }
    }
    

    在这种情况下,您想为每个可能的 x 值键入数百万个 if 语句吗?怀疑:)

    干杯!

    【讨论】:

    • +1 指出它们在功能上并不等同。
    • 如果我们在每个 if 代码块中都有返回值,它们是等价的。无效值部分不在 else 块中,而是在最后一个 if 之后的正常代码。功能上完全等同。即使没有 return 语句,我们也可以获得功能等效的代码,除了我们对每个 if 进行一次额外检查(尽管一个好的编译器也可以删除它)
    【解决方案4】:

    这完全取决于您要测试的条件。在您的示例中,最终不会有任何区别,但作为最佳实践,如果您希望最终执行其中一个条件,那么您最好使用 if else

    if (x > 1) {
        System.out.println("Hello!");
    }else if (x < 1) {
        System.out.println("Bye!");
    }
    

    另请注意,如果第一个条件为 TRUE,则根本不会检查第二个条件,但如果您使用

    if (x > 1) {
        System.out.println("Hello!");
    }
    if (x < 1) {
        System.out.println("Bye!");
    }
    

    即使第一个条件为真,也会检查第二个条件。这可能最终由优化器解决,但据我所知,它的行为方式是这样的。此外,第一个是要编写的,并且行为是这样的,因此除非逻辑另有要求,否则它始终是我的最佳选择。

    【讨论】:

      【解决方案5】:

      ifelse if 不同于两个连续的 if 语句。首先,当 CPU 采用第一个 if 分支时,不会检查 else if。在连续的两个if语句中,即使第一个if被查取,如果条件为真,下一个if也会被查取。

      【讨论】:

        【解决方案6】:

        我倾向于认为在代码更改时使用else if 更容易更健壮。如果有人要调整函数的控制流并用副作用替换返回或用try-catch 替换函数调用,如果所有条件都真正排他,else-if 将很难失败。这在很大程度上取决于您正在使用的确切代码来做出一般判断,并且您需要考虑可能的权衡取舍。

        【讨论】:

          【解决方案7】:

          在每个 if 分支中使用 return 语句。

          在您的代码中,每个 if 条件中都有 return 语句。当你遇到这样的情况时,有两种写法。第一个是您在示例 1 中的编写方式:

          if (a == b1) {
             return c1;
          } else if (a == b2) {
             return c2;
          } else {
             return c11;
          }
          

          另一种如下:

          if (a == b1) {
             return c1;
          }
          if (a == b2) {
             return c2;
          }
          return c11; // no if or else around this return statement
          

          这两种编写代码的方式是相同的。

          您在示例 2 中编写代码的方式无法在 C++ 或 Java 中编译(并且在 C 中是未定义的行为),因为编译器不知道您已经覆盖了 a 的所有可能值,所以它认为有一个通过函数的代码路径可以让你到达函数的末尾而不返回返回值。

          if (a == b1) {
             return c1;
          }
          if (a == b2) {
             return c2;
          }
          ...
          if (a == b11) {
             return c11;
          }
          // what if you set a to some value c12?
          

          每个if 分支中没有return 语句。

          如果在每个 if 分支中没有 return 语句,只有当以下语句为真时,您的代码才会在功能上相同:

          1. 您不能在任何if 分支中改变a 的值。
          2. == 是一种等价关系(在数学意义上),b1b11 都不属于同一个等价类。
          3. == 没有任何副作用。

          进一步澄清第 2 点(以及第 3 点):

          • == 在 C 或 Java 中始终是等价关系,并且永远不会产生副作用。
          • 在允许覆盖 == 运算符的语言中,例如 C++、Ruby 或 Scala,覆盖的 == 运算符可能不是等价关系,并且可能有副作用。我们当然希望重写 == 运算符的人足够清醒,可以编写一个没有副作用的等价关系,但不能保证。
          • 在 JavaScript 和某些其他类型转换规则松散的编程语言中,语言中内置了 == 不传递或不对称的情况。 (在 Javascript 中,=== 是等价关系。)

          就性能而言,示例#1 保证不会在匹配之后执行任何比较。编译器可能会优化 #2 以跳过额外的比较,但这不太可能。在下面的例子中,它可能不能,如果字符串很长,额外的比较并不便宜。

          if (strcmp(str, "b1") == 0) {
            ...
          }
          if (strcmp(str, "b2") == 0) {
            ...
          }
          if (strcmp(str, "b3") == 0) {
            ...
          }
          

          【讨论】:

            【解决方案8】:

            我更喜欢 if/else 结构,因为在每个变体中连同开关一起评估问题的所有可能状态要容易得多。我发现它更健壮并且调试速度更快,尤其是当您在 PHP 等弱类型环境中执行多个布尔评估时,例如为什么 elseif 不好(为演示而夸大):

            if(a && (c == d))
            {
            } elseif ( b && (!d || a))
            {
            } elseif ( d == a && ( b^2 > c))
            {
            } else {
            }
            

            这个问题有超过 4^2=16 个布尔状态,这只是为了演示使事情变得更糟的弱类型效应。不难想象一个三态变量,三变量问题涉及到if ab elseif bc这种方式。

            将优化留给编译器。

            【讨论】:

              【解决方案9】:

              在大多数情况下,使用 if-elseif-else 和 switch 语句而不是 if-if-if 语句更有效(因为它使编译器更容易创建跳转/查找表)和更好的实践,因为它使您的代码更具可读性,加上编译器确保您在开关中包含默认情况。此答案以及此table 比较三种不同陈述是使用此页面上的其他答案帖子以及类似 SO question 的帖子综合而成的。

              【讨论】:

                【解决方案10】:

                我认为这些代码 sn-ps 是等效的,原因很简单,因为您有许多 return 语句。如果您有一个 return 语句,您将使用这里不必要的 else 构造。

                【讨论】:

                  【解决方案11】:

                  您的比较依赖于 if 语句的主体从方法返回控制权这一事实。否则,功能会有所不同。

                  在这种情况下,它们执行相同的功能。在我看来,后者更容易阅读和理解,是我使用的选择。

                  【讨论】:

                    【解决方案12】:

                    他们可能会做不同的事情。

                    如果a 等于b1b2,则输入两个if 块。在第一个示例中,您只能输入一个。我想第一个示例更快,因为编译器可能必须按顺序检查每个条件,因为某些比较规则可能适用于对象。它也许可以优化它们......但如果你只想输入一个,第一种方法更明显,不太可能导致开发人员错误或低效代码,所以我绝对推荐。

                    【讨论】:

                      【解决方案13】:

                      CanSpice 的回答是正确的。性能的另一个考虑因素是找出最常出现的条件。例如,如果 a==b1 仅出现 1% 的时间,那么通过先检查另一种情况,您可以获得更好的性能。

                      Gir Loves Tacos 的回答也不错。最佳做法是确保涵盖所有案例。

                      【讨论】:

                        猜你喜欢
                        • 2010-10-01
                        • 1970-01-01
                        • 1970-01-01
                        • 1970-01-01
                        • 2016-02-16
                        • 2019-06-27
                        • 1970-01-01
                        • 2022-06-15
                        • 1970-01-01
                        相关资源
                        最近更新 更多