最近,我遇到了一个静态代码分析工具 (PMD) 抱怨switch
语句分支太少的情况。它建议把它变成一个 if 语句,我不想这样做,因为我知道很快就会添加更多的案例。但我想知道是否javac
执行了这样的优化。我使用 JAD 反编译了代码,但它仍然显示一个开关。这可能是 JIT 优化的运行时吗?
更新:请不要被我的问题的上下文误导。我不是在问 PMD,我不是在问是否需要微优化等。问题显然只是这样:当前(Oracle 1.6.x)JVM 实现是否包含一个处理开关的 JIT是否有几个分支。
最近,我遇到了一个静态代码分析工具 (PMD) 抱怨switch
语句分支太少的情况。它建议把它变成一个 if 语句,我不想这样做,因为我知道很快就会添加更多的案例。但我想知道是否javac
执行了这样的优化。我使用 JAD 反编译了代码,但它仍然显示一个开关。这可能是 JIT 优化的运行时吗?
更新:请不要被我的问题的上下文误导。我不是在问 PMD,我不是在问是否需要微优化等。问题显然只是这样:当前(Oracle 1.6.x)JVM 实现是否包含一个处理开关的 JIT是否有几个分支。
确定 JIT 编译器如何优化 switch 语句的方法是:
请注意,与所有与性能和优化相关的问题一样,答案取决于硬件平台以及 JVM 供应商和版本。
如果这个问题是“纯粹的好奇心”,那就这样吧。
但是,还应该指出,重写代码以使用switch
或if
出于性能原因可能是一个坏主意和/或浪费时间。
这可能是浪费时间,因为原始版本和手动优化版本之间的时间差异(如果有的话)可能微不足道。
这是一个坏主意,因为您的优化可能只对特定的硬件和 JVM 组合有帮助。在其他人身上,它可能没有效果......甚至是反优化。
简而言之,即使您知道 JIT 优化器如何处理这个问题,您也可能不应该在您的编程中考虑到它。
(当然,例外情况是当您遇到真正可衡量的性能问题时,并且分析指出(例如)3 分支switch
是瓶颈之一。)
如果你是在debug模式下编译的,反编译的时候还是能拿到switch是很正常的。否则,任何调试尝试都会遗漏一些信息,例如行号和原始指令流。
因此,您可以尝试在生产模式下编译并查看反编译结果。
然而,switch 语句,特别是如果它预计会增长,通常被认为是代码异味,应该被评估为重构的良好候选者。
至于在你澄清问题是什么之后。
由于这对硬件和 JVM 有很大的影响(使用 Java 商标的 JVM 可能由 Oracle 以外的公司开发,只要它们遵守 JVM 规范)我说唯一有效的方法是进行速度测试。
剪下一段代码,将其锁定在一个循环中进行大量重复,检查循环执行前后的时间。对两种解决方案重复(switch 和 if)
这可能看起来简单而愚蠢,但它确实有效,并且比反编译、读取字节码和内存转储等要快得多。
您必须记住,Java 实际上使用虚拟机和字节码。我很确定这一切都得到了处理和优化。我们正在使用高级语言来避免您询问的此类微观管理和优化
在更一般的说明中,我认为您尝试优化有点为时过早。如果你知道在那个开关中会有更多的案例,为什么还要麻烦呢?您是否运行了分析器?如果没有,它没有用优化。“过早的优化是万恶之源”。您可能正在优化实际上不是瓶颈的代码部分,增加代码复杂性并浪费您自己的时间编写无任何贡献的代码。
我不知道你正在制作什么类型的应用程序,但经验法则说清晰是王道,你通常应该选择更简单、更优雅、自我记录的解决方案。
javac 性能几乎没有优化。所有优化都是在运行时使用 JIT 执行的。除非您知道自己有性能问题,否则我会假设您没有。
PMD 抱怨的是清晰度。例如
if (a == 5) {
// something
} else {
// something else
}
比
switch(a) {
case 5:
// something
break;
default:
// something else
break;
}