Java - 条件跳转 switch
前言
探究 switch
语句在 JVM 里是如何执行的.
switch 语句
首先先写个 Java 代码
private static final Random random = new Random();
// ...
private static void statement() {
int result;
switch (random.nextInt(3)) {
case 0: {
result = 0;
break;
}
case 1: {
result = 1;
break;
}
case 2: {
result = 2;
break;
}
default: {
result = -1;
break;
}
}
System.out.println(result);
}
查看编译后字节码
pc bytecode
0 getstatic #18 <xianzhan/java/base/lang/Switch.random>
3 iconst_3
4 invokevirtual #22 <java/util/Random.nextInt>
7 tableswitch 0 to 2
0: 32 (+25)
1: 37 (+30)
2: 42 (+35)
default: 47 (+40)
32 iconst_0
33 istore_0
34 goto 49 (+15)
37 iconst_1
38 istore_0
39 goto 49 (+10)
42 iconst_2
43 istore_0
44 goto 49 (+5)
47 iconst_m1
48 istore_0
49 getstatic #28 <java/lang/System.out>
52 iload_0
53 invokevirtual #34 <java/io/PrintStream.println>
56 return
根据上面字节码, 我们可以看到主要的字节码就是 tableswitch
tableswitch
tableswitch 用于 switch
条件跳转, 且 case
值连续(变长指令), 也就是执行完 case
代码块里的指令就会根据是否有 break
跳转到对应的字节码执行.
switch 表达式
JEP 325: Switch Expressions (Preview)
JEP 354: Switch Expressions (Second Preview)
JEP 361: Switch Expressions
switch 表达式在 JDK 12 中可以添加参数 --enable-preview
开启, 在 JDK 14 中已经成为正式不需要开启.
使用 switch 表达式简化上面写法
private static void expression() {
int result = switch (random.nextInt(3)) {
case 0 -> 0;
case 1 -> 1;
case 2 -> 2;
default -> -1;
};
System.out.println(result);
}
查看字节码
pc bytecode
0 getstatic #18 <xianzhan/java/base/lang/condition/Switch.random>
3 iconst_3
4 invokevirtual #22 <java/util/Random.nextInt>
7 tableswitch 0 to 2
0: 32 (+25)
1: 36 (+29)
2: 40 (+33)
default: 44 (+37)
32 iconst_0
33 goto 45 (+12)
36 iconst_1
37 goto 45 (+8)
40 iconst_2
41 goto 45 (+4)
44 iconst_m1
45 istore_0
46 getstatic #28 <java/lang/System.out>
49 iload_0
50 invokevirtual #34 <java/io/PrintStream.println>
53 return
当然, 如果 case
代码块有行语句, 那怎么返回呢? 这时我们可以使用新的关键字 yield
private static void mulExpression() {
int result = switch (random.nextInt(3)) {
case 0 -> {
System.out.println(0);
yield 0;
}
case 1 -> {
System.out.println(1);
yield 1;
}
case 2 -> {
System.out.println(2);
yield 2;
}
default -> {
System.out.println("default");
yield -1;
}
};
System.out.println(result);
}