我一直习惯于使用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的答案也不错。最佳做法是确保您涵盖了所有案例。