为什么我们使用if,else-if而不是多个if块,如果主体是一个return语句
Why we use if, else if instead of multiple if block if the body is a return statement
我一直习惯于使用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-elseif-else
语句一旦找到正确的语句,就会停止进行比较。if-if-if
进行每一次比较。第一种更有效。
编辑:评论中指出,您在每个if
块中执行一个return
。在这些情况下,或者在控制将离开方法的情况下(例外),执行多个if
语句和执行if-elseif-else
语句没有区别。
然而,无论如何,最好使用if-elseif-else
。假设您更改代码,使您不在每个if
块中执行return
。然后,为了保持效率,您还必须更改为if-elseif-else
习惯用法。从一开始就将其设为if-elseif-else
可以节省您将来的编辑,并且对阅读您的代码的人来说更清晰(通过浏览您的代码,可以看到我刚才对您的误解!)。
b1 == b2
的情况如何?(如果是a == b1
和a == 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-else
或switch-case
进行一个测试。
如果您希望多个案例具有不同的功能,则使用多个if
块作为单独的测试。
这不是一个"最佳实践"的问题,而是定义你是有一个测试还是有多个测试。
在功能上不等效。
它在功能上等效的唯一方法是对a的每一个可能值执行"if"语句(即:每个可能的int值,如C中limites.h中所定义;使用int_MIN和int_MAX,或Java中的等效值)。
else语句允许您覆盖所有可能的剩余值,而不必编写数百万个"if"语句。
此外,使用if…else-if…else是更好的编码实践,就像在switch/case语句中,如果你不提供"默认"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语句?对此表示怀疑:)
干杯!
这完全取决于您正在测试的条件。在你的例子中,它最终不会有什么不同,但作为最佳实践,如果你想最终执行其中一个条件,那么你最好使用if else
if (x > 1) {
System.out.println("Hello!");
}else if (x < 1) {
System.out.println("Bye!");
}
还要注意,如果第一个条件为真,则第二个条件根本不会被检查,但如果您使用
if (x > 1) {
System.out.println("Hello!");
}
if (x < 1) {
System.out.println("Bye!");
}
即使第一个条件为TRUE,也将检查第二个条件。优化器最终可能会解决这个问题,但据我所知,它的行为是这样的。另外,第一个是这样写和表现的,所以它总是我的最佳选择,除非逻辑另有要求。
if
和else if
不同于两个连续的if
语句。在第一种情况下,当CPU执行第一个if
分支时,不会检查else if
。在连续的两个if
语句中,即使第一个if
被检查并获取,如果条件为true,则下一个if
也将被检查并获得。
我倾向于认为在代码更改时使用else if
更容易、更健壮。如果有人调整函数的控制流,并将返回替换为副作用,或者将函数调用替换为try-catch
,那么如果所有条件都是真正排他性的,则else-if
将很难失败。这在很大程度上取决于你正在使用的确切代码来做出一般判断,你需要简洁地考虑可能的权衡。
在每个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
语句,则只有当以下语句为真时,代码的功能才会完全相同:
- 在任何
if
分支中,a
的值都不会发生变化 ==
是一个等价关系(在数学意义上),并且b1
到b11
都不在同一等价类中==
没有任何副作用
为了进一步澄清第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) {
...
}
我更喜欢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
类型的方式涉及。
将优化留给编译器。
我认为这些代码片段是等效的,原因很简单,因为您有许多return
语句。如果您只有一个return
语句,那么您将使用这里不必要的else
构造。
您的比较依赖于if语句体从方法返回控制这一事实。否则,功能将有所不同。
在这种情况下,它们执行相同的功能。在我看来,后者更容易阅读和理解,是我的选择。
它们可能会做不同的事情。
如果a
等于b1
和b2
,则输入两个if
块。在第一个示例中,您只输入一个。我认为第一个例子更快,因为编译器可能必须按顺序检查每个条件,因为某些比较规则可能适用于对象。它可能能够优化它们。。。但如果你只想输入一个,第一种方法更明显,不太可能导致开发人员错误或代码效率低下,所以我绝对建议你这样做。
Gir Loves Tacos的答案也不错。最佳做法是确保您涵盖了所有案例。
- 我的简单if-else语句是如何无法访问的代码
- 如何将enable-if与模板参数和参数包一起使用
- 无论条件是否为true,if总是在c++中执行
- Arduino:for/while/if在void setup()或void loop()之前?——错误:之前需要不合格
- Insert函数不适用于2 if语句C++
- If语句未被求值C++
- C++嵌套if语句,基本货币交换
- 多个If语句与使用逻辑运算符计算条件的单个语句的比较
- 是否可以使用if constexpr删除控制流语句
- 要与"if constexpr"一起使用的编译时消息(在预处理器之后)
- 如何删除peer if else分支中的冗长句子
- 无法理解此 return 语句的功能,没有它就会发生运行时错误
- 我似乎对if/else的基本语句有问题:/
- if数组上的随机数
- 将按位if条件转换为普通if条件
- If语句在c++中被忽略
- 为什么我不能在我的三元表达式中使用 return,但我可以在常规的 if-else 语句中使用?
- 写入`for(x:y)if(p(x))return x;`以现代算法形式
- 为什么我们使用if,else-if而不是多个if块,如果主体是一个return语句
- 优雅的"if(T t = ...) { } else return t;"方式?