简单的lambda结构被内联代码替换

时间:2017-12-11 13:13:03

标签: java lambda java-8

我在高性能代码中使用这些简单的lambda接口。

@FunctionalInterface
public interface Block<T> {
    T apply() throws Exception;
}

@FunctionalInterface
public interface Block1 {
    void apply() throws Exception;
}

final void func1(final Block1 b){ my implementation ...}; 
final <T> func(final Block<T> b){ my implementation ...};

我问:源代码的jdk字节代码如

func(()->{ generic code inside }); 

Object ret=func(()->{ generic code ... return result })

被替换为内联块?

2 个答案:

答案 0 :(得分:2)

在考虑Java运行时性能时,字节码(接近)无关紧要。

因为即时编译器决定在运行时生成什么样的机器代码。

如果它找到你的方法内联,它将会这样做 - 无论字节码是什么。

如果它发现你的方法经常被调用到JIT&#39;那么它们的实现无论如何都不重要。

从这个意义上讲:为了理解代码的真实运行时行为,你必须做两件事:A)研究 JIT 的工作方式(参见例如here和B)运行时分析。要了解您的数据和代码在配置中确实发生了什么。

如果您询问lambdas的工作原理:通常使用 invokedynamic 字节码指令调用它们(请参阅here了解荣耀详情)。

答案 1 :(得分:1)

,lambda不会在字节代码中创建内联块。

请参阅Java Language Specification: 15.27.4. Run-Time Evaluation of Lambda Expressions

  

在运行时,lambda表达式的评估类似于   在正常情况下评估类实例创建表达式   完成生成对象的引用。评估一个lambda   表达式与lambda体的执行不同。

这是一个简单的测试程序,用于查看创建的字节代码。 为此我们有一个接口和一个简单的主类。

Block.java

@FunctionalInterface
public interface Block<T> {
    T apply() throws Exception;
}

Main.java

public class Main {
    public static void main(String[] args) throws Exception {
        String foobar = func(() -> "Hello World");
        System.out.println(foobar);
    }

    final static <T> T func(final Block<T> b) throws Exception {
        return b.apply();
    }
}

编译它,现在您可以使用javap来查看字节码:

javap -verbose Block.class打印:

Classfile Block.class
  Last modified 11.12.2017; size 331 bytes
  MD5 checksum d6e4627f60a7cb24b7f23064c156ede6
  Compiled from "Block.java"
public interface Block<T extends java.lang.Object>
  minor version: 0
  major version: 52
  flags: ACC_PUBLIC, ACC_INTERFACE, ACC_ABSTRACT
Constant pool:
   #1 = Class              #2             // Block
   #2 = Utf8               Block
   #3 = Class              #4             // java/lang/Object
   #4 = Utf8               java/lang/Object
   #5 = Utf8               apply
   #6 = Utf8               ()Ljava/lang/Object;
   #7 = Utf8               Exceptions
   #8 = Class              #9             // java/lang/Exception
   #9 = Utf8               java/lang/Exception
  #10 = Utf8               Signature
  #11 = Utf8               ()TT;
  #12 = Utf8               SourceFile
  #13 = Utf8               Block.java
  #14 = Utf8               <T:Ljava/lang/Object;>Ljava/lang/Object;
  #15 = Utf8               RuntimeVisibleAnnotations
  #16 = Utf8               Ljava/lang/FunctionalInterface;
{
  public abstract T apply() throws java.lang.Exception;
    descriptor: ()Ljava/lang/Object;
    flags: ACC_PUBLIC, ACC_ABSTRACT
    Exceptions:
      throws java.lang.Exception
    Signature: #11                          // ()TT;
}
SourceFile: "Block.java"
Signature: #14                          // <T:Ljava/lang/Object;>Ljava/lang/Object;
RuntimeVisibleAnnotations:
  0: #16()

javap -verbose Main.class打印:

Classfile Main.class
  Last modified 11.12.2017; size 1512 bytes
  MD5 checksum 73ceb403dfcecbf4dbb5e03ec2fe852d
  Compiled from "Main.java"
public class Main
  minor version: 0
  major version: 52
  flags: ACC_PUBLIC, ACC_SUPER
Constant pool:
   #1 = Class              #2             // Main
   #2 = Utf8               Main
   #3 = Class              #4             // java/lang/Object
   #4 = Utf8               java/lang/Object
   #5 = Utf8               <init>
   #6 = Utf8               ()V
   #7 = Utf8               Code
   #8 = Methodref          #3.#9          // java/lang/Object."<init>":()V
   #9 = NameAndType        #5:#6          // "<init>":()V
  #10 = Utf8               LineNumberTable
  #11 = Utf8               LocalVariableTable
  #12 = Utf8               this
  #13 = Utf8               LMain;
  #14 = Utf8               main
  #15 = Utf8               ([Ljava/lang/String;)V
  #16 = Utf8               Exceptions
  #17 = Class              #18            // java/lang/Exception
  #18 = Utf8               java/lang/Exception
  #19 = NameAndType        #20:#21        // apply:()LBlock;
  #20 = Utf8               apply
  #21 = Utf8               ()LBlock;
  #22 = InvokeDynamic      #0:#19         // #0:apply:()LBlock;
  #23 = Methodref          #1.#24         // Main.func:(LBlock;)Ljava/lang/Object;
  #24 = NameAndType        #25:#26        // func:(LBlock;)Ljava/lang/Object;
  #25 = Utf8               func
  #26 = Utf8               (LBlock;)Ljava/lang/Object;
  #27 = Class              #28            // java/lang/String
  #28 = Utf8               java/lang/String
  #29 = Fieldref           #30.#32        // java/lang/System.out:Ljava/io/PrintStream;
  #30 = Class              #31            // java/lang/System
  #31 = Utf8               java/lang/System
  #32 = NameAndType        #33:#34        // out:Ljava/io/PrintStream;
  #33 = Utf8               out
  #34 = Utf8               Ljava/io/PrintStream;
  #35 = Methodref          #36.#38        // java/io/PrintStream.println:(Ljava/lang/String;)V
  #36 = Class              #37            // java/io/PrintStream
  #37 = Utf8               java/io/PrintStream
  #38 = NameAndType        #39:#40        // println:(Ljava/lang/String;)V
  #39 = Utf8               println
  #40 = Utf8               (Ljava/lang/String;)V
  #41 = Utf8               args
  #42 = Utf8               [Ljava/lang/String;
  #43 = Utf8               foobar
  #44 = Utf8               Ljava/lang/String;
  #45 = Utf8               Signature
  #46 = Utf8               <T:Ljava/lang/Object;>(LBlock<TT;>;)TT;
  #47 = InterfaceMethodref #48.#50        // Block.apply:()Ljava/lang/Object;
  #48 = Class              #49            // Block
  #49 = Utf8               Block
  #50 = NameAndType        #20:#51        // apply:()Ljava/lang/Object;
  #51 = Utf8               ()Ljava/lang/Object;
  #52 = Utf8               b
  #53 = Utf8               LBlock;
  #54 = Utf8               LocalVariableTypeTable
  #55 = Utf8               LBlock<TT;>;
  #56 = Utf8               lambda$0
  #57 = Utf8               ()Ljava/lang/String;
  #58 = String             #59            // Hello World
  #59 = Utf8               Hello World
  #60 = Utf8               SourceFile
  #61 = Utf8               Main.java
  #62 = Utf8               BootstrapMethods
  #63 = Methodref          #64.#66        // 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;
  #64 = Class              #65            // java/lang/invoke/LambdaMetafactory
  #65 = Utf8               java/lang/invoke/LambdaMetafactory
  #66 = NameAndType        #67:#68        // 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;
  #67 = Utf8               metafactory
  #68 = 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;
  #69 = MethodHandle       #6:#63         // 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;
  #70 = MethodType         #51            //  ()Ljava/lang/Object;
  #71 = Methodref          #1.#72         // Main.lambda$0:()Ljava/lang/String;
  #72 = NameAndType        #56:#57        // lambda$0:()Ljava/lang/String;
  #73 = MethodHandle       #6:#71         // invokestatic Main.lambda$0:()Ljava/lang/String;
  #74 = MethodType         #57            //  ()Ljava/lang/String;
  #75 = Utf8               InnerClasses
  #76 = Class              #77            // java/lang/invoke/MethodHandles$Lookup
  #77 = Utf8               java/lang/invoke/MethodHandles$Lookup
  #78 = Class              #79            // java/lang/invoke/MethodHandles
  #79 = Utf8               java/lang/invoke/MethodHandles
  #80 = Utf8               Lookup
{
  public Main();
    descriptor: ()V
    flags: ACC_PUBLIC
    Code:
      stack=1, locals=1, args_size=1
         0: aload_0
         1: invokespecial #8                  // Method java/lang/Object."<init>":()V
         4: return
      LineNumberTable:
        line 2: 0
      LocalVariableTable:
        Start  Length  Slot  Name   Signature
            0       5     0  this   LMain;

  public static void main(java.lang.String[]) throws java.lang.Exception;
    descriptor: ([Ljava/lang/String;)V
    flags: ACC_PUBLIC, ACC_STATIC
    Exceptions:
      throws java.lang.Exception
    Code:
      stack=2, locals=2, args_size=1
         0: invokedynamic #22,  0             // InvokeDynamic #0:apply:()LBlock;
         5: invokestatic  #23                 // Method func:(LBlock;)Ljava/lang/Object;
         8: checkcast     #27                 // class java/lang/String
        11: astore_1
        12: getstatic     #29                 // Field java/lang/System.out:Ljava/io/PrintStream;
        15: aload_1
        16: invokevirtual #35                 // Method java/io/PrintStream.println:(Ljava/lang/String;)V
        19: return
      LineNumberTable:
        line 4: 0
        line 5: 12
        line 6: 19
      LocalVariableTable:
        Start  Length  Slot  Name   Signature
            0      20     0  args   [Ljava/lang/String;
           12       8     1 foobar   Ljava/lang/String;

  static final <T extends java.lang.Object> T func(Block<T>) throws java.lang.Exception;
    descriptor: (LBlock;)Ljava/lang/Object;
    flags: ACC_STATIC, ACC_FINAL
    Exceptions:
      throws java.lang.Exception
    Signature: #46                          // <T:Ljava/lang/Object;>(LBlock<TT;>;)TT;
    Code:
      stack=1, locals=1, args_size=1
         0: aload_0
         1: invokeinterface #47,  1           // InterfaceMethod Block.apply:()Ljava/lang/Object;
         6: areturn
      LineNumberTable:
        line 9: 0
      LocalVariableTable:
        Start  Length  Slot  Name   Signature
            0       7     0     b   LBlock;
      LocalVariableTypeTable:
        Start  Length  Slot  Name   Signature
            0       7     0     b   LBlock<TT;>;
}
SourceFile: "Main.java"
BootstrapMethods:
  0: #69 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:
      #70 ()Ljava/lang/Object;
      #73 invokestatic Main.lambda$0:()Ljava/lang/String;
      #74 ()Ljava/lang/String;
InnerClasses:
     public static final #80= #76 of #78; //Lookup=class java/lang/invoke/MethodHandles$Lookup of class java/lang/invoke/MethodHandles

你可以看到,对于lambda,它会创建一个

#73 invokestatic Main.lambda$0:()Ljava/lang/String;

也用

调用该块
#22 = InvokeDynamic      #0:#19         // #0:apply:()LBlock;