每天一分钟来一颗Java语法糖(一)语法糖介绍

每天一分钟来一颗Java语法糖(一)语法糖介绍

语法糖简介

语法糖(Syntactic Sugar/SyntaxSugar),也称糖衣语法,是由英国计算机学家 Peter.J.Landin(彼得·兰丁) 发明的一个术语,指在计算机语言中添加的某种语法,这种语法对语言的功能并没有影响,但是更方便程序员使用。语法糖就是对现有语法的一个封装。简而言之,语法糖让程序更加简洁,有更高的可读性。

维基百科介绍如下

In computer science, syntactic sugar is syntax within a programminglanguage that is designed to make things easier to read or to express。

语法糖好处

  • 语法糖使得程序员更容易编写程序,更清晰准确表达业务逻辑。
  • 不仅仅是语法的转换,还包括一些小的改进。

解语法糖

Java虚拟机并不支持语法糖。语法糖在编译阶段就会被还原成简单的基础语法结构,这个过程就是解语法糖。
Java中的语法糖只存在于编译期,在编译器将 .java 源文件编译成 .class 字节码时(javac命令)。
例如查看自动拆箱自动装箱的字节码,图片来自自动拆箱自动装箱
在这里插入图片描述
实际上源码还是简单的基础语法结构

如果查看com.sun.tools.javac.main.JavaCompiler的源码,就会发现在compile()中有一个步骤就是调用desugar(),这个方法就是负责解语法糖而实现的。
以下是来自笔者$JAVA_HOME/lib/tools.jar包内的com.sun.tools.javac.main.JavaCompiler类中的源码

public void compile(List<JavaFileObject> var1, List<String> var2, Iterable<? extends Processor> var3) {
   if (var3 != null && var3.iterator().hasNext()) {
       this.explicitAnnotationProcessingRequested = true;
   }

   if (this.hasBeenUsed) {
       throw new AssertionError("attempt to reuse JavaCompiler");
   } else {
       this.hasBeenUsed = true;
       this.options.put(Option.XLINT_CUSTOM.text + "-" + LintCategory.OPTIONS.option, "true");
       this.options.remove(Option.XLINT_CUSTOM.text + LintCategory.OPTIONS.option);
       this.start_msec = now();

       try {
           this.initProcessAnnotations(var3);
           this.delegateCompiler = this.processAnnotations(this.enterTrees(this.stopIfError(CompileState.PARSE, this.parseFiles(var1))), var2);
           this.delegateCompiler.compile2();
           this.delegateCompiler.close();
           this.elapsed_msec = this.delegateCompiler.elapsed_msec;
       } catch (Abort var8) {
           if (this.devVerbose) {
               var8.printStackTrace(System.err);
           }
       } finally {
           if (this.procEnvImpl != null) {
               this.procEnvImpl.close();
           }

       }

   }
}

private void compile2() {
   try {
       label44:
       switch(2.$SwitchMap$com$sun$tools$javac$main$JavaCompiler$CompilePolicy[this.compilePolicy.ordinal()]) {
       case 1:
           this.attribute((Queue)this.todo);
           break;
       case 2:
           this.flow(this.attribute((Queue)this.todo));
           break;
       case 3:
           this.generate(this.desugar(this.flow(this.attribute((Queue)this.todo))));
           break;
       case 4:
           Queue var1 = this.todo.groupByFile();

           while(true) {
               if (var1.isEmpty() || this.shouldStop(CompileState.ATTR)) {
                   break label44;
               }

               this.generate(this.desugar(this.flow(this.attribute((Queue)var1.remove()))));
           }
       case 5:
           while(true) {
               if (this.todo.isEmpty()) {
                   break label44;
               }

               this.generate(this.desugar(this.flow(this.attribute((Env)this.todo.remove()))));
           }
       default:
           Assert.error("unknown compile policy");
       }
   } catch (Abort var2) {
       if (this.devVerbose) {
           var2.printStackTrace(System.err);
       }
   }

   if (this.verbose) {
       this.elapsed_msec = elapsed(this.start_msec);
       this.log.printVerbose("total", new Object[]{Long.toString(this.elapsed_msec)});
   }

   this.reportDeferredDiagnostics();
   if (!this.log.hasDiagnosticListener()) {
       this.printCount("error", this.errorCount());
       this.printCount("warn", this.warningCount());
   }

}

public Queue<Pair<Env<AttrContext>, JCClassDecl>> desugar(Queue<Env<AttrContext>> var1) {
        ListBuffer var2 = new ListBuffer();
        Iterator var3 = var1.iterator();

        while(var3.hasNext()) {
            Env var4 = (Env)var3.next();
            this.desugar(var4, var2);
        }

        return this.stopIfError(CompileState.FLOW, (Queue)var2);
    }

    protected void desugar(Env<AttrContext> var1, Queue<Pair<Env<AttrContext>, JCClassDecl>> var2) {
        if (!this.shouldStop(CompileState.TRANSTYPES)) {
            if (this.implicitSourcePolicy != ImplicitSourcePolicy.NONE || this.inputFiles.contains(var1.toplevel.sourcefile)) {
                if (this.compileStates.isDone(var1, CompileState.LOWER)) {
                    var2.addAll((Collection)this.desugaredEnvs.get(var1));
                } else {
                    1ScanNested var3 = new 1ScanNested(this, var1);
                    var3.scan(var1.tree);
                    Iterator var4 = var3.dependencies.iterator();

                    while(var4.hasNext()) {
                        Env var5 = (Env)var4.next();
                        if (!this.compileStates.isDone(var5, CompileState.FLOW)) {
                            this.desugaredEnvs.put(var5, this.desugar(this.flow(this.attribute(var5))));
                        }
                    }

                    if (!this.shouldStop(CompileState.TRANSTYPES)) {
                        if (this.verboseCompilePolicy) {
                            this.printNote("[desugar " + var1.enclClass.sym + "]");
                        }

                        JavaFileObject var13 = this.log.useSource(var1.enclClass.sym.sourcefile != null ? var1.enclClass.sym.sourcefile : var1.toplevel.sourcefile);

                        try {
                            JCTree var14 = var1.tree;
                            this.make.at(0);
                            TreeMaker var6 = this.make.forToplevel(var1.toplevel);
                            List var7;
                            if (!(var1.tree instanceof JCCompilationUnit)) {
                                JCClassDecl var15;
                                if (this.stubOutput) {
                                    var15 = (JCClassDecl)var1.tree;
                                    if (var14 instanceof JCClassDecl && this.rootClasses.contains((JCClassDecl)var14) && ((var15.mods.flags & 5L) != 0L || var15.sym.packge().getQualifiedName() == this.names.java_lang)) {
                                        var2.add(new Pair(var1, this.removeMethodBodies(var15)));
                                    }

                                    return;
                                }

                                if (this.shouldStop(CompileState.TRANSTYPES)) {
                                    return;
                                }

                                var1.tree = this.transTypes.translateTopLevelClass(var1.tree, var6);
                                this.compileStates.put(var1, CompileState.TRANSTYPES);
                                if (this.source.allowLambda() && var3.hasLambdas) {
                                    if (this.shouldStop(CompileState.UNLAMBDA)) {
                                        return;
                                    }

                                    var1.tree = LambdaToMethod.instance(this.context).translateTopLevelClass(var1, var1.tree, var6);
                                    this.compileStates.put(var1, CompileState.UNLAMBDA);
                                }

                                if (this.shouldStop(CompileState.LOWER)) {
                                    return;
                                }

                                if (this.sourceOutput) {
                                    var15 = (JCClassDecl)var1.tree;
                                    if (var14 instanceof JCClassDecl && this.rootClasses.contains((JCClassDecl)var14)) {
                                        var2.add(new Pair(var1, var15));
                                    }

                                    return;
                                }

                                var7 = this.lower.translateTopLevelClass(var1, var1.tree, var6);
                                this.compileStates.put(var1, CompileState.LOWER);
                                if (this.shouldStop(CompileState.LOWER)) {
                                    return;
                                }

                                for(List var8 = var7; var8.nonEmpty(); var8 = var8.tail) {
                                    JCClassDecl var9 = (JCClassDecl)var8.head;
                                    var2.add(new Pair(var1, var9));
                                }

                                return;
                            }

                            if (this.stubOutput || this.sourceOutput || this.printFlat) {
                                return;
                            }

                            if (!this.shouldStop(CompileState.LOWER)) {
                                var7 = this.lower.translateTopLevelClass(var1, var1.tree, var6);
                                if (var7.head != null) {
                                    Assert.check(var7.tail.isEmpty());
                                    var2.add(new Pair(var1, (JCClassDecl)var7.head));
                                }

                                return;
                            }
                        } finally {
                            this.log.useSource(var13);
                        }

                    }
                }
            }
        }
    }

Java 中最常用的语法糖主要有switch语句支持String与枚举、泛型和类型擦除、自动装箱与拆箱、方法边长参数、枚举、内部类、条件编译、断言、数值字面量、增强for循环、try-with-resources语句、Lambda表达式等。后续逐一详细介绍

原创文章 29 获赞 41 访问量 962

猜你喜欢

转载自blog.csdn.net/lovesunren/article/details/105624744