Simple lambda structure is replaced by inline code

I use these simple lambda interfaces in high-performance code.

@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 ...}; 

I ask: jdk byte code for source code like

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

or

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

replaced by built-in blocks?

+4
source share
2 answers

Bytecode (close to) is inappropriate when considering Java runtime performance.

Because the compiler "exactly at the point in time" decides at runtime which machine code to generate.

If he finds that your methods are worth investing, he will do it - no matter what the bytecode says.

If it detects that your methods are not called often enough to expose JIT ... then their implementation does not matter.

In this sense: in order to understand the real behavior of your code at runtime, you need to do two things: A) study the work of JIT (see here ) and B) profiling at runtime. To find out what really happens in your configuration with your data and code.

And in case you ask about how lambdas work in general: they are usually called using the invokedynamic bytecode command (see here for glory details).

+2
source

No , lambda does not create inline blocks in bytecode.

See Java Language Specification: 15.27.4. Time evaluation of a lambda expression .

At run time, evaluating a lambda expression is similar to evaluating an instance of creating an instance of a class, because termination creates a reference to the object. Evaluating a lambda expression is different from performing a lambda body.


Here is a simple test program to find out which byte code is generated. For this, we have an interface and a simple main class.

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(); } } 

Compile it, now you can use javap to view the bytecode:

javap -verbose Block.class Prints:

 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 Prints:

 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 

You can see that for lambda is created

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

a block with

 #22 = InvokeDynamic #0:#19 // #0:apply:()LBlock; 
+1
source

Source: https://habr.com/ru/post/1273979/


All Articles