【Java】switch-case 和 if-else 的运行效率差异

switch-case

在 switch-case 中,case 的值是连续的话,会生成一个 TableSwitch 来进行优化,这样的情况下,只需要在表中进行判断即可。

这里使用 0-4 的连续值来进行测试

img

如果说多加几个 Case 的值,但是范围控制在比较小的范围时:

这里使用 0-9 之间的不连续的值来进行测试

img

可以发现仍然使用了一个 TableSwitch 来进行优化。继续加大范围,但是只有少数能使用到,可以看到:

img

这一部分使用了 LookupSwitch 来进行判断,可以很明显看出就是执行搜索指令来得到目标执行的代码块。那么在这种情况下,switch-case 的效率是比较低的。为什么低呢?

JVM 虚拟机规范中提到:

Compilation of switch statements uses the tableswitch and lookupswitch instructions. The tableswitch instruction is used when the cases of the switch can be efficiently represented as indices into a table of target offsets. The default target of the switch is used if the value of the expression of the switch falls outside the range of valid indices.Where the cases of the switch are sparse, the table representation of the tableswitch instruction becomes inefficient in terms of space. The lookupswitch instruction may be used instead.

The Java virtual machine specifies that the table of the lookupswitch instruction must be sorted by key so that implementations may use searches more efficient than a linear scan. Even so, the lookupswitch instruction must search its keys for a match rather than simply perform a bounds check and index into a table like tableswitch. Thus, a tableswitch instruction is probably more efficient than a lookupswitch where space considerations permit a choice.

这一部分的大意就是:

switch 语句的编译使用 tableswitch 和 lookupswitch 指令。当 switch 的情况可以有效地表示为目标偏移表中的索引时,使用 tableswitch 指令。如果 switch 表达式的值超出有效索引范围,则使用 switch 的默认目标。在 switch 的情况稀疏的情况下,tableswitch 的 table 表示在空间方面变得低效,也可以使用lookupswitch 指令。

Java虚拟机指定 lookupswitch 指令的表必须按键排序,以便实现可以使用比线性扫描更高效的搜索。即使如此,lookupswitch 指令也必须搜索其键以查找匹配项,而不是简单地执行边界检查并索引到类似 tableswitch 的表中。因此,在空间考虑允许选择的情况下,tableswitch 指令可能比 lookupswitch 更有效。

这个 tableswitch 相比 lookupswitch 的转换,什么时候才算是稀疏,这就取决于编译器的决策问题了。这一个决策,需要设计到数理统计上,找到效率的执行上的差异来决定。

如果使用的是其他的数据类型进行 switch 的判断时,可以看到这一优化仍然存在。

img

那么如果 case 之间使用的是不同数据类型呢?

使用 char 类型和 int 类型同时进行判断测试

img

结果仍然没有改变,最终的底层还是会使用的 ASCII 码进行相关计算。同理来说,如果是 String 类型,则同样换算数字来进行计算,只不过使用的是 String 的 Hashcode 方法来获取 String 的对应数值。

img

if-else

仍然使用之前的测试方法,这里使用连续的小范围的值进行测试:

img

这里可以看到使用的是逐个进行判断的方式。

再使用不连续的方式进行判断:

img

这里结论没有改变,仍然是使用的逐个判断。

结论

  • 只有在 case 中的条件是连续的或范围相隔不大(不稀疏)时,编译器会使用表结构做优化,性能优于 if-else 。
  • 其他情况下,switch-case 是逐个分支判断(lookupswitch),性能与 if-else 无异。
  • switch-case 中的 case 只能是常量,而 if-else 用途更广一些。

在选择分支较多且连续或者范围相隔不大时,选用 switch-case 结构会提高程序的效率,但switch 不足的地方在于只能处理字符或者数字类型的变量。if-else 结构更加灵活一些,if-else 结构可以用于判断表达式是否成立,应用范围更广,switch-case结构在某些情况下可以替代 if-else 结构。

编译网站:Compiler Explorer

  • 5
    点赞
  • 4
    收藏
    觉得还不错? 一键收藏
  • 4
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 4
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值