效率:switch 语句优于 if 语句
Posted
技术标签:
【中文标题】效率:switch 语句优于 if 语句【英文标题】:Efficiency: switch statements over if statements 【发布时间】:2012-05-14 13:57:55 【问题描述】:PMD
告诉我
少于3个分支的switch效率低下,使用if语句 而是。
这是为什么呢?为什么是3?他们如何定义效率?
【问题讨论】:
PMD 扫描 Java 源代码并查找潜在问题,例如可能的错误、死代码、次优代码、过于复杂的表达式和重复代码。 (将鼠标悬停在标签上) 它还应该扫描自己的语法。 “少”应该是“少”。 :) @yshavit less 合适所以也少,在这种情况下内涵就足够了。 cracked.com/blog/… 不要把你的描述性语法强加给我,@MikeMcMahon!我喜欢我的语法,就像我喜欢我的冰川一样:古老、冰冻并尽可能缓慢地移动。 强制性“过早优化是万恶之源”等 【参考方案1】:因为switch
语句是用两条特殊的JVM 指令编译的,它们是lookupswitch
和tableswitch
。它们在处理大量案例时很有用,但当您只有几个分支时它们会导致开销。
if/else
语句反而被编译成典型的 je
jne
... 链,这些链更快,但在长链分支中使用时需要更多比较。
您可以通过查看字节码来看到差异,无论如何我不会担心这些问题,如果有任何问题可能会出现问题,那么 JIT 会处理它。
实际例子:
switch (i)
case 1: return "Foo";
case 2: return "Baz";
case 3: return "Bar";
default: return null;
编译成:
L0
LINENUMBER 21 L0
ILOAD 1
TABLESWITCH
1: L1
2: L2
3: L3
default: L4
L1
LINENUMBER 23 L1
FRAME SAME
LDC "Foo"
ARETURN
L2
LINENUMBER 24 L2
FRAME SAME
LDC "Baz"
ARETURN
L3
LINENUMBER 25 L3
FRAME SAME
LDC "Bar"
ARETURN
L4
LINENUMBER 26 L4
FRAME SAME
ACONST_NULL
ARETURN
虽然
if (i == 1)
return "Foo";
else if (i == 2)
return "Baz";
else if (i == 3)
return "Bar";
else
return null;
编译成
L0
LINENUMBER 21 L0
ILOAD 1
ICONST_1
IF_ICMPNE L1
L2
LINENUMBER 22 L2
LDC "Foo"
ARETURN
L1
LINENUMBER 23 L1
FRAME SAME
ILOAD 1
ICONST_2
IF_ICMPNE L3
L4
LINENUMBER 24 L4
LDC "Baz"
ARETURN
L3
LINENUMBER 25 L3
FRAME SAME
ILOAD 1
ICONST_3
IF_ICMPNE L5
L6
LINENUMBER 26 L6
LDC "Bar"
ARETURN
L5
LINENUMBER 28 L5
FRAME SAME
ACONST_NULL
ARETURN
【讨论】:
杰克谢谢你。这是一个绝妙的答案。顺便说一句,你用什么来查看.class
文件?
这是一个Eclipse的插件,如果我没记错应该是这个:andrei.gmxhome.de/bytecode/index.html
@JAM:相信你也可以用javap。
众所周知,字节码是唯一决定性能的东西——jit永远不会改变代码来获得更好的性能!另一个无用的»性能«优化【参考方案2】:
虽然与使用 if 语句相比,使用 switch 的效率提升很小,但在大多数情况下,这些收益可以忽略不计。任何称职的源代码扫描器都会认识到micro-optimizations 是次要的代码清晰度。
他们说如果 switch 非常短,if 语句比 switch 语句更易于阅读并且占用的代码行数更少。
来自PMD website:
TooFewBranchesForASwitchStatement:Switch 语句旨在用于支持复杂的分支行为。只在少数情况下使用 switch 是不明智的,因为 switch 不像 if-then 语句那样容易理解。在这些情况下,使用 theif-then 语句来增加代码的可读性。
【讨论】:
清晰度的重要性远远超过任何微优化。毫无疑问。 好消息是他们在警告中声明“效率低下”,但他们声明它仅与文档中的“可读性”有关。良好的连贯性..【参考方案3】:这是为什么呢?
当代码(最终)被 JIT 编译器编译为本机代码时,会使用不同的指令序列。切换由执行间接分支的一系列本机指令实现。 (该序列通常从表中加载一个地址,然后分支到该地址。) if / else 被实现为评估条件的指令(可能是比较指令),然后是条件分支指令。
为什么是 3 个?
这是一个经验观察,我假设基于分析生成的本机代码指令和/或基准测试。 (或者可能没有。为了绝对确定,您需要询问该 PMD 规则的作者他们是如何得出该数字的。)
他们如何定义效率?
执行指令所花费的时间。
我个人会对这条规则提出异议……或者更准确地说,是这条信息。我认为应该说if / else
语句比带有 2 个 case 的 switch 更简单、更易读。效率问题是次要的,可能无关紧要。
【讨论】:
【参考方案4】:我认为这与 switch 和 if/else 的编译方式有关。
假设处理一个 switch 语句需要 5 次计算。假设一个 if 语句需要两次计算。开关中少于 3 个选项将等于 ifs 中的 4 个计算与开关中的 5 个计算。但是,交换机的开销保持不变,所以如果它有 3 个选择,ifs 将被 3 * 2 处理,而交换机仍然是 5。
查看数百万次计算所获得的收益是微不足道的。它更多的是“这是更好的方法”,而不是任何可能影响您的事情。它只会在一个相当迭代中在该函数上循环数百万次的东西上这样做。
【讨论】:
以上是关于效率:switch 语句优于 if 语句的主要内容,如果未能解决你的问题,请参考以下文章