Nein, Lambda erzeugt keine Inline-Blöcke im Byte-Code.
Java Language Specification: 15.27.4. Run-Time Evaluation of Lambda Expressions Siehe
Zur Laufzeit Auswertung eines Lambda-Ausdrucks ist ähnlich Auswertung einer Klasseninstanz Schaffung Ausdruck, soweit normale Abschluss eine Referenz auf ein Objekt erzeugt. Die Auswertung einer Lambda Expression unterscheidet sich von der Ausführung des Lambda-Körpers.
Hier ist ein einfaches Testprogramm zu sehen, welche Byte-Code erstellt wird. Dafür haben wir eine Schnittstelle und eine einfache Hauptklasse.
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();
}
}
es Kompilieren, jetzt können Sie javap
verwenden den Bytecode zu lesen:
javap -verbose Block.class
druckt:
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
druckt:
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
Sie, dass für den Lambda sehen sie eine
#73 invokestatic Main.lambda$0:()Ljava/lang/String;
schafft auch der Block mit
#22 = InvokeDynamic #0:#19 // #0:apply:()LBlock;
Afaik, kompiliert der Code zu nicht inlined bytecode, eine Klasse pro Lambda. Die JVM kann jedoch während der JIT-Kompilierung eine Inlining-Operation durchführen, was sie insbesondere bei stark verwendetem Code oft tut. – xs0
Haben Sie versucht, den erstellten Byte-Code zu überprüfen? Sie können dies mit [javap] (https://docs.oracle.com/javase/8/docs/technotes/tools/windows/javap.html) tun. – devpuh
ein bisschen irreführend ... meinst du 'inline' (wie in einer Methode wird in eine andere inline?), denn aus Ihrer Frage scheint es, als ob Sie fragen, ob eine Instanz eines Lambda zwischengespeichert wird. Also welches ist es? – Eugene