概念
1.语法糖Syntactic Sugar,也称糖衣语法,指计算机语言中添加某种语法,这种语法对语言的功能没有影响,但程序员使用更方便。在java中即JVM并不识别,会在编译器进行解析,还原成基础语法。
2.由com.sum.tools.javac.main.JavaCompiler中的deSugger方法,负责解析语法糖。
具体实现
java常见的语法糖包括:条件编译、断言、Switch语句与枚举及字符串结合、可变参数、自动装箱/拆箱、枚举、内部类、泛型擦除、增强for循环、lambda表达式、try-with-resources语句、JDK10的局部变量类型推断等等。
这里我借助另一个反编译工具 CFR 来分析java中的语法糖, 这里我下载的是最新的cfr_0_132.jar。
字符串拼接
public void stringBuilderTest() {
System.out.println("aa"+x+"bb"+"cc");
System.out.println("aa"+"bb"+"cc");
for(int i = 0; i < 1000; i++) {
System.out.println("aa"+x+"bb"+"cc");
}
}
// 编译后
// public void stringBuilderTest() {
// System.out.println(new StringBuilder().append("aa").append(this.x).append("bbcc").toString());
// System.out.println("aabbcc");
// for (int i = 0; i < 1000; ++i) {
// System.out.println(new StringBuilder().append("aa").append(this.x).append("bbcc").toString());
// }
// }
命令行: java -jar cfr-0.150.jar SyntacticSugar.class --stringbuilder false
1.从反编译后的代码中能看出, 当我们使用+号进行字符串拼接操作时, 编译时会自动创建一个StringBuilder对象。所以当在循环中拼接字符串时, 应避免使用+号操作, 否则每次循环都会创建一个StringBuilder对象再回收, 造成较大的开销。
2.可以看到对于字符串常量的拼接,在编译期就会自动拼接好,无需等待运行期。
条件编译
public void ifCompilerTest() {
if(true) {
System.out.println("is True");
}else {
System.out.println("is False");
}
}
// 编译后
// public void ifCompilerTest() {
// System.out.println("is True");
// }
命令行: java -jar cfr-0.150.jar SyntacticSugar.class
很明显, 编译器在编译时期的解语法糖阶段, 会将条件分支不成立的代码进行消除。
断言
public void assertTest(String s) {
assert (!s.equals("aaaa"));
System.out.println(s);
}
// 编译后
// public void assertTest(String s) {
// if (!$assertionsDisabled && s.equals("aaaa")) {
// throw new AssertionError();
// }
// System.out.println(s);
// }
命令行: java -jar cfr-0.150.jar SyntacticSugar.class --sugarasserts false
如上, 当断言结果为true时, 程序继续正常执行, 当断言结果为false时, 则抛出AssertionError异常来打断程序的执行。
枚举与Switch语句
public enum EnumTest {
FOO,
BAR,
BAP
}
public int switchEnumTest(EnumTest e) {
switch (e) {
case FOO:
return 1;
case BAP:
return 2;
}
return 0;
}
// 编译后
// public int switchEnumTest(EnumTest e) {
// switch (1.$SwitchMap$com$qcloud$midware$hugo$syntactic$sugar$SyntacticSugar$EnumTest[e.ordinal()]) {
// case 1: {
// return 1;
// }
// case 2: {
// return 2;
// }
// }
// return 0;
// }
命令行: java -jar cfr-0.150.jar SyntacticSugar.class --decodeenumswitch false
switch支持枚举是通过调用枚举类默认继承的父类Enum中的ordinal()方法来实现的, 这个方法会返回枚举常量的序数。
字符串与Switch语句