关于java:效率:切换if语句的语句

Efficiency: switch statements over if statements

PMD告诉我

A switch with less than 3 branches is inefficient, use a if statement
instead.

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


因为switch语句是用lookupswitchtableswitch两个特殊的JVM指令编译的。它们在处理许多情况时很有用,但是当您只有很少的分支时,它们会导致开销。

一个if/else语句被编译成典型的jejne语句。在长的分支链中使用时,速度更快但需要更多比较的链。

您可以通过查看字节代码来查看差异,在任何情况下,我都不会担心这些问题,如果有任何问题可能成为问题,那么JIT将处理它。

实例:

1
2
3
4
5
6
7
switch (i)
{
  case 1: return"Foo";
  case 2: return"Baz";
  case 3: return"Bar";
  default: return null;
}

编译为:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
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

同时

1
2
3
4
5
6
7
8
if (i == 1)
  return"Foo";
else if (i == 2)
  return"Baz";
else if (i == 3)
  return"Bar";
else
  return null;

被编译成

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
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


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

他们说,如果switch非常短,那么if语句比switch语句更容易读取,占用的代码行也更少。

从PMD网站:

TooFewBranchesForASwitchStatement: Switch statements are indended to be used to support complex branching behaviour. Using a switch for only a few cases is ill-advised, since switches are not as easy to understand as if-then statements. In these cases use theif-then statement to increase code readability.


Why is that?

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

Why 3?

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

How do they define efficiency?

执行指令所用的时间。

我个人会反对这条规则…或者更准确地说是关于信息。我认为应该说一个if / else语句比一个包含两个事例的开关更简单、更易读。效率问题是次要的,可能无关紧要。


我认为这与开关和if/else的编译方式有关。

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

当看到数以百万计的计算时,收益是极其微不足道的。更重要的是"这是更好的方法"而不是任何可能影响你的事情。它只能在一个相当迭代中,在这个函数上循环数百万次。