30

PMD告诉我

少于 3 个分支的 switch 效率低下,请改用 if 语句。

这是为什么?为什么是3?他们如何定义效率?

4

4 回答 4

39

因为一条switch语句是用两个特殊的 JVM 指令编译的,它们是lookupswitchtableswitch。它们在处理大量案例时很有用,但当您只有几个分支时它们会导致开销。

相反,一条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
于 2012-05-05T04:06:48.823 回答
7

尽管与使用 if 语句相比,使用 switch 的效率提升很小,但在大多数情况下,这些收益可以忽略不计。任何称职的源代码扫描器都会认识到微优化是代码清晰度的次要因素。

他们说如果 switch 非常短,if 语句比 switch 语句更易于阅读并且占用的代码行数更少。

来自PMD 网站

TooFewBranchesForASwitchStatement:Switch 语句旨在用于支持复杂的分支行为。只在少数情况下使用 switch 是不明智的,因为 switch 不像 if-then 语句那样容易理解。在这些情况下,使用 theif-then 语句来增加代码的可读性。

于 2012-05-05T04:04:08.963 回答
6

这是为什么?

当 JIT 编译器(最终)将代码编译为本机代码时,会使用不同的指令序列。切换由执行间接分支的一系列本机指令实现。(该序列通常从表中加载一个地址,然后分支到该地址。) if / else 被实现为评估条件的指令(可能是比较指令),然后是条件分支指令。

为什么是3?

这是一个经验观察,我假设基于分析生成的本机代码指令和/或基准测试。(或者可能不是。为了绝对确定,您需要询问该 PMD 规则的作者他们是如何得出该数字的。)

他们如何定义效率?

执行指令所花费的时间。


我个人会对这条规则提出异议……或者更准确地说,是这条信息。我认为应该说一个if / else语句比带有 2 个 case 的 switch 更简单、更易读。效率问题是次要的,可能无关紧要。

于 2012-05-05T04:06:52.270 回答
1

我相信这与 switch 和 if/else 的编译方式有关。

假设处理一个 switch 语句需要 5 次计算。假设一个 if 语句需要两次计算。您的 switch 中少于 3 个选项将等于 ifs 中的 4 个计算与 switch 中的 5 个计算。但是,交换机中的开销保持不变,因此如果它有 3 个选择,则 ifs 将被 3 * 2 处理,而交换机仍然为 5。

查看数百万次计算所获得的收益是极其微不足道的。它更多的是“这是更好的方法”,而不是任何可能影响您的事情。它只会在一个相当迭代中在该函数上循环数百万次的东西上这样做。

于 2012-05-05T04:04:33.600 回答