如何编译Java lambda函数?

时间:2013-05-30 03:01:22

标签: java lambda java-8

Loop.times(5, () -> {
   System.out.println("looping");
});

它有效地编译到哪个?

for(int i = 0; i < 5; i++)
    System.out.println("looping");

或类似

new CallableInterfaceImpl(){
    public void call(){
      for(int i = 0; i < 5; i++)
          System.out.println("looping");
    }
}.call();

那么它会替换(内联类),还是实际创建一个匿名类?

3 个答案:

答案 0 :(得分:47)

VM决定如何实现lambda,而不是编译器。

请参阅Translation of Lambda Expressions中的Translation strategy部分。

  

我们不是生成字节码来创建实现lambda表达式的对象(例如调用内部类的构造函数),而是描述构造lambda的配方,并将实际构造委托给语言运行库。该配方在invokedynamic指令的静态和动态参数列表中进行编码。

从简单的编译或性能来看,

for构造是最有效的方法(但是测试中的性能差异非常小)。

插件

我创建并反汇编了两个例子:

for (String string: Arrays.asList("hello")) {
    System.out.println(string);
}

反汇编的字节码,常量和其他信息:

Classfile LambdaCode.class
  Last modified 30.05.2013; size 771 bytes
  MD5 checksum 79bf2821b5a14485934e5cebb60c99d6
  Compiled from "LambdaCode.java"
public class test.lambda.LambdaCode
  SourceFile: "LambdaCode.java"
  minor version: 0
  major version: 52
  flags: ACC_PUBLIC, ACC_SUPER
Constant pool:
   #1 = Methodref          #11.#22        //  java/lang/Object."<init>":()V
   #2 = Class              #23            //  java/lang/String
   #3 = String             #24            //  hello
   #4 = Methodref          #25.#26        //  java/util/Arrays.asList:([Ljava/lang/Object;)Ljava/util/List;
   #5 = InterfaceMethodref #27.#28        //  java/util/List.iterator:()Ljava/util/Iterator;
   #6 = InterfaceMethodref #29.#30        //  java/util/Iterator.hasNext:()Z
   #7 = InterfaceMethodref #29.#31        //  java/util/Iterator.next:()Ljava/lang/Object;
   #8 = Fieldref           #32.#33        //  java/lang/System.out:Ljava/io/PrintStream;
   #9 = Methodref          #34.#35        //  java/io/PrintStream.println:(Ljava/lang/String;)V
  #10 = Class              #36            //  test/lambda/LambdaCode
  #11 = Class              #37            //  java/lang/Object
  #12 = Utf8               <init>
  #13 = Utf8               ()V
  #14 = Utf8               Code
  #15 = Utf8               LineNumberTable
  #16 = Utf8               main
  #17 = Utf8               ([Ljava/lang/String;)V
  #18 = Utf8               StackMapTable
  #19 = Class              #38            //  java/util/Iterator
  #20 = Utf8               SourceFile
  #21 = Utf8               LambdaCode.java
  #22 = NameAndType        #12:#13        //  "<init>":()V
  #23 = Utf8               java/lang/String
  #24 = Utf8               hello
  #25 = Class              #39            //  java/util/Arrays
  #26 = NameAndType        #40:#41        //  asList:([Ljava/lang/Object;)Ljava/util/List;
  #27 = Class              #42            //  java/util/List
  #28 = NameAndType        #43:#44        //  iterator:()Ljava/util/Iterator;
  #29 = Class              #38            //  java/util/Iterator
  #30 = NameAndType        #45:#46        //  hasNext:()Z
  #31 = NameAndType        #47:#48        //  next:()Ljava/lang/Object;
  #32 = Class              #49            //  java/lang/System
  #33 = NameAndType        #50:#51        //  out:Ljava/io/PrintStream;
  #34 = Class              #52            //  java/io/PrintStream
  #35 = NameAndType        #53:#54        //  println:(Ljava/lang/String;)V
  #36 = Utf8               test/lambda/LambdaCode
  #37 = Utf8               java/lang/Object
  #38 = Utf8               java/util/Iterator
  #39 = Utf8               java/util/Arrays
  #40 = Utf8               asList
  #41 = Utf8               ([Ljava/lang/Object;)Ljava/util/List;
  #42 = Utf8               java/util/List
  #43 = Utf8               iterator
  #44 = Utf8               ()Ljava/util/Iterator;
  #45 = Utf8               hasNext
  #46 = Utf8               ()Z
  #47 = Utf8               next
  #48 = Utf8               ()Ljava/lang/Object;
  #49 = Utf8               java/lang/System
  #50 = Utf8               out
  #51 = Utf8               Ljava/io/PrintStream;
  #52 = Utf8               java/io/PrintStream
  #53 = Utf8               println
  #54 = Utf8               (Ljava/lang/String;)V
{
  public test.lambda.LambdaCode();
    descriptor: ()V
    flags: ACC_PUBLIC
    Code:
      stack=1, locals=1, args_size=1
         0: aload_0       
         1: invokespecial #1                  // Method java/lang/Object."<init>":()V
         4: return        
      LineNumberTable:
        line 15: 0

  public static void main(java.lang.String[]);
    descriptor: ([Ljava/lang/String;)V
    flags: ACC_PUBLIC, ACC_STATIC
    Code:
      stack=4, locals=3, args_size=1
         0: iconst_1      
         1: anewarray     #2                  // class java/lang/String
         4: dup           
         5: iconst_0      
         6: ldc           #3                  // String hello
         8: aastore       
         9: invokestatic  #4                  // Method java/util/Arrays.asList:([Ljava/lang/Object;)Ljava/util/List;
        12: invokeinterface #5,  1            // InterfaceMethod java/util/List.iterator:()Ljava/util/Iterator;
        17: astore_1      
        18: aload_1       
        19: invokeinterface #6,  1            // InterfaceMethod java/util/Iterator.hasNext:()Z
        24: ifeq          47
        27: aload_1       
        28: invokeinterface #7,  1            // InterfaceMethod java/util/Iterator.next:()Ljava/lang/Object;
        33: checkcast     #2                  // class java/lang/String
        36: astore_2      
        37: getstatic     #8                  // Field java/lang/System.out:Ljava/io/PrintStream;
        40: aload_2       
        41: invokevirtual #9                  // Method java/io/PrintStream.println:(Ljava/lang/String;)V
        44: goto          18
        47: return        
      LineNumberTable:
        line 35: 0
        line 36: 37
        line 37: 44
        line 38: 47
      StackMapTable: number_of_entries = 2
           frame_type = 252 /* append */
             offset_delta = 18
        locals = [ class java/util/Iterator ]
           frame_type = 250 /* chop */
          offset_delta = 28

}

Arrays.asList("hello").forEach(p -> {System.out.println(p);});

反汇编的字节码,常量和其他信息:

Classfile LambdaCode.class
  Last modified 30.05.2013; size 1262 bytes
  MD5 checksum 4804e0a37b73141d5791cc39d51d649c
  Compiled from "LambdaCode.java"
public class test.lambda.LambdaCode
  SourceFile: "LambdaCode.java"
  InnerClasses:
       public static final #64= #63 of #70; //Lookup=class java/lang/invoke/MethodHandles$Lookup of class java/lang/invoke/MethodHandles
  BootstrapMethods:
    0: #27 invokestatic java/lang/invoke/LambdaMetafactory.metaFactory:(Ljava/lang/invoke/MethodHandles$Lookup;Ljava/lang/String;Ljava/lang/invoke/MethodType;Ljava/lang/invoke/MethodHandle;Ljava/lang/invoke/MethodHandle;Ljava/lang/invoke/MethodType;)Ljava/lang/invoke/CallSite;
      Method arguments:
        #28 invokeinterface java/util/function/Consumer.accept:(Ljava/lang/Object;)V
        #29 invokestatic test/lambda/LambdaCode.lambda$0:(Ljava/lang/String;)V
        #30 (Ljava/lang/String;)V
  minor version: 0
  major version: 52
  flags: ACC_PUBLIC, ACC_SUPER
Constant pool:
   #1 = Methodref          #10.#21        //  java/lang/Object."<init>":()V
   #2 = Class              #22            //  java/lang/String
   #3 = String             #23            //  hello
   #4 = Methodref          #24.#25        //  java/util/Arrays.asList:([Ljava/lang/Object;)Ljava/util/List;
   #5 = InvokeDynamic      #0:#31         //  #0:lambda$:()Ljava/util/function/Consumer;
   #6 = InterfaceMethodref #32.#33        //  java/util/List.forEach:(Ljava/util/function/Consumer;)V
   #7 = Fieldref           #34.#35        //  java/lang/System.out:Ljava/io/PrintStream;
   #8 = Methodref          #36.#37        //  java/io/PrintStream.println:(Ljava/lang/String;)V
   #9 = Class              #38            //  test/lambda/LambdaCode
  #10 = Class              #39            //  java/lang/Object
  #11 = Utf8               <init>
  #12 = Utf8               ()V
  #13 = Utf8               Code
  #14 = Utf8               LineNumberTable
  #15 = Utf8               main
  #16 = Utf8               ([Ljava/lang/String;)V
  #17 = Utf8               lambda$0
  #18 = Utf8               (Ljava/lang/String;)V
  #19 = Utf8               SourceFile
  #20 = Utf8               LambdaCode.java
  #21 = NameAndType        #11:#12        //  "<init>":()V
  #22 = Utf8               java/lang/String
  #23 = Utf8               hello
  #24 = Class              #40            //  java/util/Arrays
  #25 = NameAndType        #41:#42        //  asList:([Ljava/lang/Object;)Ljava/util/List;
  #26 = Utf8               BootstrapMethods
  #27 = MethodHandle       #6:#43         //  invokestatic java/lang/invoke/LambdaMetafactory.metaFactory:(Ljava/lang/invoke/MethodHandles$Lookup;Ljava/lang/String;Ljava/lang/invoke/MethodType;Ljava/lang/invoke/MethodHandle;Ljava/lang/invoke/MethodHandle;Ljava/lang/invoke/MethodType;)Ljava/lang/invoke/CallSite;
  #28 = MethodHandle       #9:#44         //  invokeinterface java/util/function/Consumer.accept:(Ljava/lang/Object;)V
  #29 = MethodHandle       #6:#45         //  invokestatic test/lambda/LambdaCode.lambda$0:(Ljava/lang/String;)V
  #30 = MethodType         #18            //  (Ljava/lang/String;)V
  #31 = NameAndType        #46:#47        //  lambda$:()Ljava/util/function/Consumer;
  #32 = Class              #48            //  java/util/List
  #33 = NameAndType        #49:#50        //  forEach:(Ljava/util/function/Consumer;)V
  #34 = Class              #51            //  java/lang/System
  #35 = NameAndType        #52:#53        //  out:Ljava/io/PrintStream;
  #36 = Class              #54            //  java/io/PrintStream
  #37 = NameAndType        #55:#18        //  println:(Ljava/lang/String;)V
  #38 = Utf8               test/lambda/LambdaCode
  #39 = Utf8               java/lang/Object
  #40 = Utf8               java/util/Arrays
  #41 = Utf8               asList
  #42 = Utf8               ([Ljava/lang/Object;)Ljava/util/List;
  #43 = Methodref          #56.#57        //  java/lang/invoke/LambdaMetafactory.metaFactory:(Ljava/lang/invoke/MethodHandles$Lookup;Ljava/lang/String;Ljava/lang/invoke/MethodType;Ljava/lang/invoke/MethodHandle;Ljava/lang/invoke/MethodHandle;Ljava/lang/invoke/MethodType;)Ljava/lang/invoke/CallSite;
  #44 = InterfaceMethodref #58.#59        //  java/util/function/Consumer.accept:(Ljava/lang/Object;)V
  #45 = Methodref          #9.#60         //  test/lambda/LambdaCode.lambda$0:(Ljava/lang/String;)V
  #46 = Utf8               lambda$
  #47 = Utf8               ()Ljava/util/function/Consumer;
  #48 = Utf8               java/util/List
  #49 = Utf8               forEach
  #50 = Utf8               (Ljava/util/function/Consumer;)V
  #51 = Utf8               java/lang/System
  #52 = Utf8               out
  #53 = Utf8               Ljava/io/PrintStream;
  #54 = Utf8               java/io/PrintStream
  #55 = Utf8               println
  #56 = Class              #61            //  java/lang/invoke/LambdaMetafactory
  #57 = NameAndType        #62:#66        //  metaFactory:(Ljava/lang/invoke/MethodHandles$Lookup;Ljava/lang/String;Ljava/lang/invoke/MethodType;Ljava/lang/invoke/MethodHandle;Ljava/lang/invoke/MethodHandle;Ljava/lang/invoke/MethodType;)Ljava/lang/invoke/CallSite;
  #58 = Class              #67            //  java/util/function/Consumer
  #59 = NameAndType        #68:#69        //  accept:(Ljava/lang/Object;)V
  #60 = NameAndType        #17:#18        //  lambda$0:(Ljava/lang/String;)V
  #61 = Utf8               java/lang/invoke/LambdaMetafactory
  #62 = Utf8               metaFactory
  #63 = Class              #71            //  java/lang/invoke/MethodHandles$Lookup
  #64 = Utf8               Lookup
  #65 = Utf8               InnerClasses
  #66 = Utf8               (Ljava/lang/invoke/MethodHandles$Lookup;Ljava/lang/String;Ljava/lang/invoke/MethodType;Ljava/lang/invoke/MethodHandle;Ljava/lang/invoke/MethodHandle;Ljava/lang/invoke/MethodType;)Ljava/lang/invoke/CallSite;
  #67 = Utf8               java/util/function/Consumer
  #68 = Utf8               accept
  #69 = Utf8               (Ljava/lang/Object;)V
  #70 = Class              #72            //  java/lang/invoke/MethodHandles
  #71 = Utf8               java/lang/invoke/MethodHandles$Lookup
  #72 = Utf8               java/lang/invoke/MethodHandles
{
  public test.lambda.LambdaCode();
    descriptor: ()V
    flags: ACC_PUBLIC
    Code:
      stack=1, locals=1, args_size=1
         0: aload_0       
         1: invokespecial #1                  // Method java/lang/Object."<init>":()V
         4: return        
      LineNumberTable:
        line 15: 0

  public static void main(java.lang.String[]);
    descriptor: ([Ljava/lang/String;)V
    flags: ACC_PUBLIC, ACC_STATIC
    Code:
      stack=4, locals=1, args_size=1
         0: iconst_1      
         1: anewarray     #2                  // class java/lang/String
         4: dup           
         5: iconst_0      
         6: ldc           #3                  // String hello
         8: aastore       
         9: invokestatic  #4                  // Method java/util/Arrays.asList:([Ljava/lang/Object;)Ljava/util/List;
        12: invokedynamic #5,  0              // InvokeDynamic #0:lambda$:()Ljava/util/function/Consumer;
        17: invokeinterface #6,  2            // InterfaceMethod java/util/List.forEach:(Ljava/util/function/Consumer;)V
        22: return        
      LineNumberTable:
        line 28: 0
        line 38: 22
}

对于Lambda示例,编译器生成的类文件更复杂,更大(771b对1262b)。

答案 1 :(得分:0)

开发人员编写的Lambda语法已分解为编译期间生成的JVM级别指令。因此,构造lambda的实际责任将推迟到运行时。

为了使Java的编译时间更少严格,并允许JVM语言在运行时绑定代码,Java 7向JVM引入了新的invokedynamic字节码指令,并引入了新的java.lang.invoke API包。 invokedynamic通过动态方法调用促进了动态语言(对于JVM)的实现。 Lambda工程师为Lambda选择了invokedynamic方法。让我们看看Lambda被编译成什么:

程序:

package com.onlyfullstack;

public class LambdaInternalWorking {

 public static void main(String[] args) {
  Runnable runnable = () -> System.out.println("Calling from Lambda");
 }
}

让我们编译以下程序:

javac LambdaInternalWorking.java

让我们反汇编.class文件以查看内容:

javap -p LambdaInternalWorking.class

Compiled from "LambdaInternalWorking.java"
public class com.onlyfullstack.LambdaInternalWorking {
  public com.onlyfullstack.LambdaInternalWorking();
  public static void main(java.lang.String[]);
  private static void lambda$main$0();
}

在此文件中,我们看不到我们的run()方法。让我们检查类文件的Verobse,以获得更多的清晰度。

javap -verbose LambdaInternalWorking.class

Classfile onlyfullstack/LambdaInternalWorking.class
  Last modified 30 Jan, 2019; size 1023 bytes
  MD5 checksum e99d1d2d0eca865f2f46960aad7216f1
  Compiled from "LambdaInternalWorking.java"
public class com.onlyfullstack.LambdaInternalWorking
  minor version: 0
  major version: 52
  flags: ACC_PUBLIC, ACC_SUPER
Constant pool:
   #1 = Methodref          #7.#17         // java/lang/Object."<init>":()V
   #2 = InvokeDynamic      #0:#22         // #0:run:()Ljava/lang/Runnable;
   #3 = Fieldref           #23.#24        // java/lang/System.out:Ljava/io/PrintStream;
   #4 = String             #25            // Calling from Lambda
   #5 = Methodref          #26.#27        // java/io/PrintStream.println:(Ljava/lang/String;)V
   #6 = Class              #28            // com/onlyfullstack/LambdaInternalWorking
   #7 = Class              #29            // java/lang/Object
   #8 = Utf8               <init>
   #9 = Utf8               ()V
  #10 = Utf8               Code
  #11 = Utf8               LineNumberTable
  #12 = Utf8               main
  #13 = Utf8               ([Ljava/lang/String;)V
  #14 = Utf8               lambda$main$0
  #15 = Utf8               SourceFile
  #16 = Utf8               LambdaInternalWorking.java
  #17 = NameAndType        #8:#9          // "<init>":()V
  #18 = Utf8               BootstrapMethods
  #19 = MethodHandle       #6:#30         // invokestatic java/lang/invoke/LambdaMetafactory.metafactory:(Ljava/lang/invoke/MethodHandles$Lookup;Ljava/lang/String;Ljava/lang/invoke/MethodType;Ljava/lang/invoke/MethodType;Ljava/lang/invoke/MethodHandle;Ljava/lang/invoke/MethodType;)Ljava/lang/invoke/CallSite;
  #20 = MethodType         #9             //  ()V
  #21 = MethodHandle       #6:#31         // invokestatic com/onlyfullstack/LambdaInternalWorking.lambda$main$0:()V
  #22 = NameAndType        #32:#33        // run:()Ljava/lang/Runnable;
  #23 = Class              #34            // java/lang/System
  #24 = NameAndType        #35:#36        // out:Ljava/io/PrintStream;
  #25 = Utf8               Calling from Lambda
  #26 = Class              #37            // java/io/PrintStream
  #27 = NameAndType        #38:#39        // println:(Ljava/lang/String;)V
  #28 = Utf8               com/onlyfullstack/LambdaInternalWorking
  #29 = Utf8               java/lang/Object
  #30 = Methodref          #40.#41        // java/lang/invoke/LambdaMetafactory.metafactory:(Ljava/lang/invoke/MethodHandles$Lookup;Ljava/lang/String;Ljava/lang/invoke/MethodType;Ljava/lang/invoke/MethodType;Ljava/lang/invoke/MethodHandle;Ljava/lang/invoke/MethodType;)Ljava/lang/invoke/CallSite;
  #31 = Methodref          #6.#42         // com/onlyfullstack/LambdaInternalWorking.lambda$main$0:()V
  #32 = Utf8               run
  #33 = Utf8               ()Ljava/lang/Runnable;
  #34 = Utf8               java/lang/System
  #35 = Utf8               out
  #36 = Utf8               Ljava/io/PrintStream;
  #37 = Utf8               java/io/PrintStream
  #38 = Utf8               println
  #39 = Utf8               (Ljava/lang/String;)V
  #40 = Class              #43            // java/lang/invoke/LambdaMetafactory
  #41 = NameAndType        #44:#48        // metafactory:(Ljava/lang/invoke/MethodHandles$Lookup;Ljava/lang/String;Ljava/lang/invoke/MethodType;Ljava/lang/invoke/MethodType;Ljava/lang/invoke/MethodHandle;Ljava/lang/invoke/MethodType;)Ljava/lang/invoke/CallSite;
  #42 = NameAndType        #14:#9         // lambda$main$0:()V
  #43 = Utf8               java/lang/invoke/LambdaMetafactory
  #44 = Utf8               metafactory
  #45 = Class              #50            // java/lang/invoke/MethodHandles$Lookup
  #46 = Utf8               Lookup
  #47 = Utf8               InnerClasses
  #48 = Utf8               (Ljava/lang/invoke/MethodHandles$Lookup;Ljava/lang/String;Ljava/lang/invoke/MethodType;Ljava/lang/invoke/MethodType;Ljava/lang/invoke/MethodHandle;Ljava/lang/invoke/MethodType;)Ljava/lang/invoke/CallSite;
  #49 = Class              #51            // java/lang/invoke/MethodHandles
  #50 = Utf8               java/lang/invoke/MethodHandles$Lookup
  #51 = Utf8               java/lang/invoke/MethodHandles
{
  public com.onlyfullstack.LambdaInternalWorking();
    descriptor: ()V
    flags: ACC_PUBLIC
    Code:
      stack=1, locals=1, args_size=1
         0: aload_0
         1: invokespecial #1                  // Method java/lang/Object."<init>":()V
         4: return
      LineNumberTable:
        line 3: 0

  public static void main(java.lang.String[]);
    descriptor: ([Ljava/lang/String;)V
    flags: ACC_PUBLIC, ACC_STATIC
    Code:
      stack=1, locals=2, args_size=1
         0: invokedynamic #2,  0              // InvokeDynamic #0:run:()Ljava/lang/Runnable;
         5: astore_1
         6: return
      LineNumberTable:
        line 6: 0
        line 7: 6
}
SourceFile: "LambdaInternalWorking.java"
InnerClasses:
     public static final #46= #45 of #49; //Lookup=class java/lang/invoke/MethodHandles$Lookup of class java/lang/invoke/MethodHandles
BootstrapMethods:
  0: #19 invokestatic java/lang/invoke/LambdaMetafactory.metafactory:(Ljava/lang/invoke/MethodHandles$Lookup;Ljava/lang/String;Ljava/lang/invoke/MethodType;Ljava/lang/invoke/MethodType;Ljava/lang/invoke/MethodHandle;Ljava/lang/invoke/MethodType;)Ljava/lang/invoke/CallSite;
    Method arguments:
      #20 ()V
      #21 invokestatic com/onlyfullstack/LambdaInternalWorking.lambda$main$0:()V
      #20 ()V

我们不需要了解整个文件,我们只需要检查黄色突出显示的代码即可。从第73-80行开始,包含用public static void main()方法编写的代码。在第78行,JVM正在对第10行的id#2进行invokedynamic调用,因此,此调用实际上将插入run方法并执行它,而无需创建Anonymous类。

有关更多信息,请参见以下链接: https://onlyfullstack.blogspot.com/2019/02/lambda-expression-tutorial-in-java-8.html

https://onlyfullstack.blogspot.com/2019/02/how-lambda-internally-works-in-java-8.html

答案 2 :(得分:0)

Java编译器将为未显式或隐式声明的代码构造生成综合方法

我们知道,lambda表达式/函数是函数接口中抽象方法的匿名类方法实现,如果我们看到带有lambda表达式的已编译类文件的字节码,则无需创建一个新对象来包装Lambda函数,它使用新的 INVOKEDYNAMIC 指令将此调用站点动态链接到实际Lambda函数,该函数将转换为private static synthetic lambda$0(Ljava/lang/String;)V,它将接受字符串作为参数

private static synthetic lambda$0(Ljava/lang/String;)V GETSTAIC java/lang/System.out: Ljava/io/PrintStream; ALOAD 0 INVOKEVIRTUAL java/io/PrintStream.println(Ljava/lang/String;)V RETURN

示例:list.forEach(x-> System.out.println(x));

如上所述,该lambda表达式x-> System.out.println(x)被转换为私有静态合成块。 但是当我们运行Java类时,如何对列表中的每个元素调用此方法?,因为forEach接受了Consumer功能接口对象,请参考下面的lambda表达式链接字节代码。

INVOKEDYNAMIC accept()Ljava/util/function/Consumer; [ java/lang/invoke/LambdaMetaFactory.metafactory(Ljava/lang/invokeMethodHandler$Lookup.Ljava/lang/invoke/CallSite.. //arguments (Ljava/lang/Object;)V //INVOKESTATIC com/<Classname>.lambda$)(Ljava/lang/String;)V, (Ljava/lang/String;)V ]

java.lang.invoke.LambdaMetaFactory :此类提供了两种形式的链接方法:

  1. 使用优化协议的标准版本(元(方法(MethodHandles.Lookup,String,MethodType,MethodType,MethodHandle,MethodType)))
  2. 替代版本altMetafactory(MethodHandles.Lookup,String,MethodType,Object ...))。

这些链接方法旨在支持对Java语言中的lambda表达式和方法引用进行求值。 对于源代码中的每个lambda表达式或方法引用,都有一个目标类型,它是一个功能接口。 计算lambda表达式会产生其目标类型的对象。推荐的评估lambda表达式的机制是将lambda主体解糖为一种方法,调用一个invokedynamic调用站点,该站点的静态参数列表描述了功能接口的唯一方法和已废止的实现方法,并返回一个对象(lambda对象)实现目标类型。 注意(对于方法引用,实现方法只是被引用的方法;无需重复使用。)