我在高性能代码中使用这些简单的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 })
被替换为内联块?
答案 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;