用于字符串切换
class Fun {
static int fun(String s) {
switch (s) {
case "I":
return 1;
case "A":
return 2;
case "Z":
return 3;
case "ABS":
return 4;
case "IND":
return 5;
default:
return 6;
}
}
}
Oracle Java 编译器生成的字节码类似于以下代码(Eclipse Compiler for Java 生成的字节码略有不同)
int c = -1;
switch (s.hashCode()) {
case 65: // +1 branch
if (s.equals("I")) // +2 branches
c = 0;
break;
case 73: // +1 branch
if (s.equals("A")) // +2 branches
c = 1;
break;
case 90: // +1 branch
if (s.equals("Z")) // +2 branches
c = 2;
break;
case 64594: // +1 branch
if (s.equals("ABS")) // +2 branches
c = 3;
break;
case 72639: // +1 branch
if (s.equals("IND")) // +2 branches
c = 4;
break;
default: // +1 branch
}
switch (c) {
case 0: // +1 branch
return 1;
case 1: // +1 branch
return 2;
case 2: // +1 branch
return 3;
case 3: // +1 branch
return 4;
case 4: // +1 branch
return 5;
default: // +1 branch
return 6;
}
因此,具有 6 个 case 的原始 switch 语句在字节码中由一个 switch 表示,该 switch 具有 6 个 case 的 hashCode 或 String 加上 5 个 if 语句加上另一个具有 6 个 case 的 switch。要查看此字节码,您可以使用javap -c。
JaCoCo 执行字节码分析,并且在低于 0.8.0 的版本中没有按字符串切换的过滤器。您的测试涵盖了 if 语句中的条件评估为 true 的情况,但不包括它们评估为 false 的情况。就个人而言,我建议简单地忽略丢失的情况,因为目标不是测试编译器生成正确的代码,而是测试您的应用程序是否正确运行。但是为了这个答案的完整性 - 这里是涵盖所有字节码分支的测试:
import org.junit.Test;
import static org.junit.Assert.*;
public class FunTest {
@Test
public void test() {
// original strings:
assertEquals(1, Fun.fun("I"));
assertEquals(2, Fun.fun("A"));
assertEquals(3, Fun.fun("Z"));
assertEquals(4, Fun.fun("ABS"));
assertEquals(5, Fun.fun("IND"));
// same hash codes, but different strings:
assertEquals(6, Fun.fun("\0I"));
assertEquals(6, Fun.fun("\0A"));
assertEquals(6, Fun.fun("\0Z"));
assertEquals(6, Fun.fun("\0ABS"));
assertEquals(6, Fun.fun("\0IND"));
// distinct hash code to cover default cases of switches
assertEquals(6, Fun.fun(""));
}
}
JaCoCo 0.7.9 生成的报告作为证明:
JaCoCo version 0.8.0 provides filters,包括javac 为按字符串切换生成的字节码过滤器。因此即使没有额外的测试也会生成以下报告: