Không, lambda không tạo khối nội tuyến trong mã byte.
Xem Java Language Specification: 15.27.4. Run-Time Evaluation of Lambda Expressions
Vào lúc chạy, đánh giá của một biểu thức lambda là tương tự như đánh giá của một biểu thức tạo lớp Ví dụ, trong chừng mực bình thường hoàn thành sản xuất một tham chiếu đến một đối tượng. Đánh giá biểu thức lambda khác biệt với việc thực thi thân lambda.
Đây là một chương trình thử nghiệm đơn giản để xem những gì mã byte được tạo ra. Đối với điều này, chúng tôi có một giao diện và một lớp học chính đơn giản.
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();
}
}
Biên dịch nó, bây giờ bạn có thể sử dụng javap
để xem các bytecode:
javap -verbose Block.class
in:
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
in:
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
Bạn có thể thấy rằng đối với các lambda nó tạo ra một
#73 invokestatic Main.lambda$0:()Ljava/lang/String;
cũng khối được gọi với
#22 = InvokeDynamic #0:#19 // #0:apply:()LBlock;
Afaik, mã biên dịch thành bytecode không được mã hóa, một lớp cho mỗi lambda. Tuy nhiên, JVM có thể làm nội tuyến trong thời gian chạy trong quá trình biên dịch JIT, mà nó thường làm, đặc biệt là trong mã được sử dụng nhiều. – xs0
Bạn đã thử kiểm tra mã byte đã tạo chưa? Bạn có thể làm điều này với [javap] (https://docs.oracle.com/javase/8/docs/technotes/tools/windows/javap.html) – devpuh
một chút gây hiểu nhầm ... ý bạn là 'inline' (như trong một phương thức được đưa vào một phương thức khác?) bởi vì từ câu hỏi của bạn, có vẻ như bạn đang hỏi liệu một cá thể của một lambda có được lưu trữ hay không. Vì vậy, đó là một trong nó? – Eugene