What is the function of Java lambda learning notes

Time:2021-2-11

Don’t talk about the source code

1. Main method

public static void main(String[] args) {
        Function<String, Integer> s = Integer::parseInt;
        s.apply("10");
    }

Let’s look at the next section

2. Decompile

javap -v -p StreamTest

give the result as follows

Warning: the binary streamtest contains com.cui.subject . java.function.StreamTest
Classfile /E:/WorkSpace/subject/java/target/classes/com/cui/subject/java/function/StreamTest.class
  Last modified 2020-6-15; size 1311 bytes
  MD5 checksum 7b5bc92830d2402bc0d88bfe91926d3e
  Compiled from "StreamTest.java"
public class com.cui.subject.java.function.StreamTest
  minor version: 0
  major version: 52
  flags: ACC_PUBLIC, ACC_SUPER
Constant pool:
   #1 = Methodref          #6.#24         // java/lang/Object."<init>":()V
   #2 = InvokeDynamic      #0:#30         // #0:apply:()Ljava/util/function/Function;
   #3 = String             #31            // 10
   #4 = InterfaceMethodref #32.#33        // java/util/function/Function.apply:(Ljava/lang/Object;)Ljava/lang/Object;
   #5 = Class              #34            // com/cui/subject/java/function/StreamTest
   #6 = Class              #35            // java/lang/Object
   #7 = Utf8               <init>
   #8 = Utf8               ()V
   #9 = Utf8               Code
  #10 = Utf8               LineNumberTable
  #11 = Utf8               LocalVariableTable
  #12 = Utf8               this
  #13 = Utf8               Lcom/cui/subject/java/function/StreamTest;
  #14 = Utf8               main
  #15 = Utf8               ([Ljava/lang/String;)V
  #16 = Utf8               args
  #17 = Utf8               [Ljava/lang/String;
  #18 = Utf8               s
  #19 = Utf8               Ljava/util/function/Function;
  #20 = Utf8               LocalVariableTypeTable
  #21 = Utf8               Ljava/util/function/Function<Ljava/lang/String;Ljava/lang/Integer;>;
  #22 = Utf8               SourceFile
  #23 = Utf8               StreamTest.java
  #24 = NameAndType        #7:#8          // "<init>":()V
  #25 = Utf8               BootstrapMethods
  #26 = MethodHandle       #6:#36         // 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;
  #27 = MethodType         #37            //  (Ljava/lang/Object;)Ljava/lang/Object;
  #28 = MethodHandle       #6:#38         // invokestatic java/lang/Integer.parseInt:(Ljava/lang/String;)I
  #29 = MethodType         #39            //  (Ljava/lang/String;)Ljava/lang/Integer;
  #30 = NameAndType        #40:#41        // apply:()Ljava/util/function/Function;
  #31 = Utf8               10
  #32 = Class              #42            // java/util/function/Function
  #33 = NameAndType        #40:#37        // apply:(Ljava/lang/Object;)Ljava/lang/Object;
  #34 = Utf8               com/cui/subject/java/function/StreamTest
  #35 = Utf8               java/lang/Object
  #36 = Methodref          #43.#44        // 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;
  #37 = Utf8               (Ljava/lang/Object;)Ljava/lang/Object;
  #38 = Methodref          #45.#46        // java/lang/Integer.parseInt:(Ljava/lang/String;)I
  #39 = Utf8               (Ljava/lang/String;)Ljava/lang/Integer;
  #40 = Utf8               apply
  #41 = Utf8               ()Ljava/util/function/Function;
  #42 = Utf8               java/util/function/Function
  #43 = Class              #47            // java/lang/invoke/LambdaMetafactory
  #44 = NameAndType        #48:#52        // 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;
  #45 = Class              #53            // java/lang/Integer
  #46 = NameAndType        #54:#55        // parseInt:(Ljava/lang/String;)I
  #47 = Utf8               java/lang/invoke/LambdaMetafactory
  #48 = Utf8               metafactory
  #49 = Class              #57            // java/lang/invoke/MethodHandles$Lookup
  #50 = Utf8               Lookup
  #51 = Utf8               InnerClasses
  #52 = 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;
  #53 = Utf8               java/lang/Integer
  #54 = Utf8               parseInt
  #55 = Utf8               (Ljava/lang/String;)I
  #56 = Class              #58            // java/lang/invoke/MethodHandles
  #57 = Utf8               java/lang/invoke/MethodHandles$Lookup
  #58 = Utf8               java/lang/invoke/MethodHandles
{
  public com.cui.subject.java.function.StreamTest();
    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 11: 0
      LocalVariableTable:
        Start  Length  Slot  Name   Signature
            0       5     0  this   Lcom/cui/subject/java/function/StreamTest;

  public static void main(java.lang.String[]);
    descriptor: ([Ljava/lang/String;)V
    flags: ACC_PUBLIC, ACC_STATIC
    Code:
      stack=2, locals=2, args_size=1
         0: invokedynamic #2,  0              // InvokeDynamic #0:apply:()Ljava/util/function/Function;
         5: astore_1
         6: aload_1
         7: ldc           #3                  // String 10
         9: invokeinterface #4,  2            // InterfaceMethod java/util/function/Function.apply:(Ljava/lang/Object;)Ljava/lang/Object;
        14: pop
        15: return
      LineNumberTable:
        line 13: 0
        line 14: 6
        line 17: 15
      LocalVariableTable:
        Start  Length  Slot  Name   Signature
            0      16     0  args   [Ljava/lang/String;
            6      10     1     s   Ljava/util/function/Function;
      LocalVariableTypeTable:
        Start  Length  Slot  Name   Signature
            6      10     1     s   Ljava/util/function/Function<Ljava/lang/String;Ljava/lang/Integer;>;
}
SourceFile: "StreamTest.java"
InnerClasses:
     public static final #50= #49 of #56; //Lookup=class java/lang/invoke/MethodHandles$Lookup of class java/lang/invoke/MethodHandles
BootstrapMethods:
  0: #26 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:
      #27 (Ljava/lang/Object;)Ljava/lang/Object;
      #28 invokestatic java/lang/Integer.parseInt:(Ljava/lang/String;)I
      #29 (Ljava/lang/String;)Ljava/lang/Integer;

3.invokedynamic

 #2 = InvokeDynamic      #0:#30         // #0:apply:()Ljava/util/function/Function;

3.10 here

BootstrapMethods:
  0: #26 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:
      #27 (Ljava/lang/Object;)Ljava/lang/Object;
      #28 invokestatic java/lang/Integer.parseInt:(Ljava/lang/String;)I
      #29 (Ljava/lang/String;)Ljava/lang/Integer;

BootstrapMethods

Each instance of an invokedynamic instruction is called a dynamic call site. The dynamic call site starts with an unlinked state (unlinked: indicating that the method to be called by the call point has not been specified). The dynamic call point depends on the boot method to link to the specific method. The boot method is generated by the compiler. When the JVM encounters the invokedynamic instruction for the first time at runtime, the, The bootstrap method is called to link the name (method name, method signature) specified by the invokedynamic instruction with the specific execution code (target method). The return value of the bootstrap method permanently determines the behavior of the calling point. The return value type of the bootstrap method is java.lang.invoke . callsite, an invokedynamic instruction is associated with a callsite, Delegate all calls to the current target (methodhandle) of callsite

LambdaMetafactory.metafactory

public static CallSite metafactory(MethodHandles.Lookup caller,
                                       String invokedName,
                                       MethodType invokedType,
                                       MethodType samMethodType,
                                       MethodHandle implMethod,
                                       MethodType instantiatedMethodType)
            throws LambdaConversionException {
        AbstractValidatingLambdaMetafactory mf;
        mf = new InnerClassLambdaMetafactory(caller, invokedType,
                                             invokedName, samMethodType,
                                             implMethod, instantiatedMethodType,
                                             false, EMPTY_CLASS_ARRAY, EMPTY_MT_ARRAY);
        mf.validateMetafactoryArgs();
        //An inner class is created here
        return mf.buildCallSite();
    }
  1. MethodHandles.Lookup Caller: represents the search context and the access permission of the caller. When invokedynamic is used, the JVM will automatically fill in this parameter
  2. String invokedname: the name of the method to be implemented. When invokedynamic is used, the JVM will automatically fill it for us (the filling content comes from the constant pool) InvokeDynamic.NameAndType.Name )Here, the JVM fills in “apply” for us Consumer.accept Method name
  3. Methodtype invokedtype: the type of method parameter expected by the calling point and the type of return value (method signature). When using the invokedynamic instruction, the JVM will automatically fill this parameter (the filling content comes from the constant pool) InvokeDynamic.NameAndType.Type )Here, the parameter is string and the return value type is consumer, which means that the parameter of the target method of the call point is string, After invokedynamic is executed, a consumer instance will be returned
  4. Methodtype sammethodtype: the interface method type to be implemented by the function object. At runtime, the value is (object) object Consumer.accept Method type (generic information erased). # (ljava / Lang / object;) V
  5. Methodhandle implmethod: a direct method handle, which describes the specific implementation method to be executed when calling (including appropriate parameter adaptation, return type adaptation, and additional captured parameters before calling parameters). In this case, # 70 invokestatic Lambda.lambda $0: (ljava / Lang / string;) method handle of V method
  6. Methodtype instantiatedmethodtype: the method type of a function interface method after replacing the generic type with a specific type. It is usually the same as sammethodtype. The different cases are generic type:

4.5.6 three parameters

  #27 (Ljava/lang/Object;)Ljava/lang/Object;
      #28 invokestatic java/lang/Integer.parseInt:(Ljava/lang/String;)I
      #29 (Ljava/lang/String;)Ljava/lang/Integer;
//An inner class is created here
return mf.buildCallSite();

The generated inner classes are as follows
Add this sentence

System.setProperty("jdk.internal.lambda.dumpProxyClasses", "E:\WorkSpace\subject\lambda\");

Internal classes will be generated in the specified directory, as follows

final class StreamTest$$Lambda$1 implements Function {
    private StreamTest$$Lambda$1() {
    }

    @Hidden
    public Object apply(Object var1) {
        return Integer.parseInt((String)var1);
    }
}

If it is such a code

new Thread(() ->  System.out.println (thread:+ Thread.currentThread ().getId())).start();

The generated inner class looks like this

final class StreamTest$$Lambda$1 implements Runnable {
    private StreamTest$$Lambda$1() {
    }

    @Hidden
    public void run() {
        StreamTest.lambda$main$0();
    }
}

How about this

 Consumer<String> consumer = Integer::parseInt;

That’s what it looks like

final class StreamTest$$Lambda$1 implements Consumer {
    private StreamTest$$Lambda$1() {
    }

    @Hidden
    public void accept(Object var1) {
        Integer.parseInt((String)var1);
    }
}

How about this

 public static void main(String[] args) {
        Func add = (x, y) -> x + y;
        System.out.println(add.exec(1, 2));
    }

    @FunctionalInterface
    interface Func {
        int exec(int x, int y);
    }

That’s what it looks like

final class StreamTest$$Lambda$1 implements Func {
    private StreamTest$$Lambda$1() {
    }

    @Hidden
    public int exec(int var1, int var2) {
        return StreamTest.lambda$main$0(var1, var2);
    }
}

3.2 30 here

On behalf of which method

#30 = NameAndType        #40:#41        // apply:()Ljava/util/function/Function;

summary

Lambda expression, using the invokedynamic instruction, called at runtime LambdaMetafactory.metafactory Dynamic generation of internal classes to achieve the interface
The calling method block in the inner class is not generated dynamically, but a static method has been compiled in the original class, and the inner class only needs to call the static method