为何Java枚举switch首次执行比if等价实现慢得多?
为何Java的枚举switch首次执行比等价的if实现慢得多?
我了解JVM需要进行“warm-up”后才能可靠地测量性能,因此首次调用比后续调用慢得多,但这并不意味着我们无法基于首次执行来测量性能。
测试标准
- 始终执行全新运行。
- 以nanoseconds为单位测量单个函数的执行时间,该函数根据传入值通过
if语句或switch语句返回整数。 - 存储返回值并在最后打印,避免其被优化丢弃。
测试结果
枚举测试
77596nanoseconds - if实现585232nanoseconds - switch实现
为确认是否仅枚举存在该问题,我还测试了整数和字符串(Java 7起支持字符串switch):
整数测试:
2308nanoseconds - if实现1950nanoseconds - switch实现
字符串测试:
8517nanoseconds - if实现8322nanoseconds - switch实现
这两项测试结果相近,表明if与switch语句在各次运行中性能相当,但枚举的情况并非如此。我在Windows、Linux平台,Java 8和Java 17版本下均进行了测试。
测试代码
枚举switch实现代码
public class SwitchEnum{ public static void main(String[] args){ long st = System.nanoTime(); int val = getValue(Day.FRIDAY); long en = System.nanoTime(); System.out.println("SwitchEnum perf nano: " + (en - st)); System.out.println("Sum: " + val); } public static int getValue(Day day){ switch (day){ case MONDAY: return 7; case TUESDAY: return 3; case WEDNESDAY: return 5; case THURSDAY: return 2; case FRIDAY: return 1; case SATURDAY: return 6; case SUNDAY: return 4; default: throw new RuntimeException(); } } }
枚举if实现代码
public class IfEnum{ public static void main(String[] args){ long st = System.nanoTime(); int val = getValue(Day.FRIDAY); long en = System.nanoTime(); System.out.println("IfEnum perf nano: " + (en - st)); System.out.println("Sum: " + val); } public static int getValue(Day day){ if (day == Day.MONDAY){ return 7; }else if (day == Day.TUESDAY){ return 3; }else if (day == Day.WEDNESDAY){ return 5; }else if (day == Day.THURSDAY){ return 2; }else if (day == Day.FRIDAY){ return 1; }else if (day == Day.SATURDAY){ return 6; }else if (day == Day.SUNDAY){ return 4; }else{ throw new RuntimeException(); } } }
枚举Day定义
public enum Day{ MONDAY, TUESDAY, WEDNESDAY, THURSDAY, FRIDAY, SATURDAY, SUNDAY; }
补充说明与疑问
我也在C和C#中测试了枚举switch与if的性能,未发现显著差异。同时注意到添加default或else分支可提升性能,因此所有测试均包含该分支。
本问题并非讨论常规的“if vs switch”性能对比,而是聚焦枚举与switch语句组合的异常表现。为何枚举switch的首次执行平均比等价if慢7倍?其性能开销的来源是什么?
似乎我被误解了,最初的枚举完全不同,为找到“不合理开销”的根源,我设计了此基准测试。有趣的是,预热JVM对该函数的性能毫无帮助。即使在目标方法前添加嵌套循环:
添加预热逻辑后的测试代码
public static void main(String[] args) throws InterruptedException{ for (int i = 0; i < 1000; i++){ for (int j = 0; j < 1000; j++){ System.out.println(j); } System.out.println(i); } Thread.sleep(100); for (int i = 0; i < 1000; i++){ System.out.println(i); } long st = System.nanoTime(); int val = getValue(Day.FRIDAY); long en = System.nanoTime(); System.out.println("SwitchEnum perf nano: " + (en - st)); System.out.println("Sum: " + val); }
唯一影响性能的是该方法是否已被调用过,后续调用都会被优化。例如框架初始化时,initialize()方法仅被调用一次,此时首次调用的性能至关重要。假设框架启动时调用8000个方法,每个耗时1ms,总耗时8秒,而枚举switch比if多增加0.6ms开销,这是不合理的。因此我想询问,该性能开销的根源是什么?
内容的提问来源于stack exchange,提问作者Mr Monitor
相关产品推荐
相关产品推荐

