For example, I have two lambdas:
Runnable exec1 = () -> {
System.out.print("Hi from lambda");
};
Runnable exec2 = () -> {
System.out.print("Hi from lambda");
};
Invokedynamic operator will create it with special factory
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;
But I have some problems with bytecode reading. Does it mean, that in this case this factory will cache lambda creation (and exec2
will reuse instance)?
// access flags 0x9
public static main([Ljava/lang/String;)V
L0
LINENUMBER 6 L0
INVOKEDYNAMIC run()Ljava/lang/Runnable; [
// handle kind 0x6 : 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;
// arguments:
()V,
// handle kind 0x6 : INVOKESTATIC
test/Main.lambda$main$0()V,
()V
]
ASTORE 1
L1
LINENUMBER 10 L1
INVOKEDYNAMIC run()Ljava/lang/Runnable; [
// handle kind 0x6 : 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;
// arguments:
()V,
// handle kind 0x6 : INVOKESTATIC
test/Main.lambda$main$1()V,
()V
]
ASTORE 2
L2
LINENUMBER 13 L2
RETURN
L3
LOCALVARIABLE args [Ljava/lang/String; L0 L3 0
LOCALVARIABLE exec Ljava/lang/Runnable; L1 L3 1
LOCALVARIABLE exec2 Ljava/lang/Runnable; L2 L3 2
MAXSTACK = 1
MAXLOCALS = 3
// access flags 0x100A
private static synthetic lambda$main$1()V
L0
LINENUMBER 11 L0
GETSTATIC java/lang/System.out : Ljava/io/PrintStream;
LDC "Hi from lambda"
INVOKEVIRTUAL java/io/PrintStream.print (Ljava/lang/String;)V
L1
LINENUMBER 12 L1
RETURN
MAXSTACK = 2
MAXLOCALS = 0
// access flags 0x100A
private static synthetic lambda$main$0()V
L0
LINENUMBER 7 L0
GETSTATIC java/lang/System.out : Ljava/io/PrintStream;
LDC "Hi from lambda"
INVOKEVIRTUAL java/io/PrintStream.print (Ljava/lang/String;)V
L1
LINENUMBER 8 L1
RETURN
MAXSTACK = 2
MAXLOCALS = 0
}
You need to understand what a call-site
is, first, imo; to be able to understand where caching happens. Both exec1
and exec2
will create two separate instances of a Runnable
interface; both will be cached on the call-site
. May be this little snippet will help:
public static void main(String[] args) {
useStatelessLambda1();
useStatelessLambda1();
useStatelessLambda2();
useStatelessLambda2();
}
static void useStatelessLambda1() {
Runnable exec1 = () -> {
System.out.print("Hi from lambda");
};
System.out.print(exec1.hashCode() + " ");
exec1.run();
System.out.println("\n");
}
static void useStatelessLambda2() {
Runnable exec2 = () -> {
System.out.print("Hi from lambda");
};
System.out.print(exec2.hashCode() + " ");
exec2.run();
System.out.println("\n");
}
Running this reveals:
1878246837 Hi from lambda
1878246837 Hi from lambda
1995265320 Hi from lambda
1995265320 Hi from lambda
separate instances, but both cached on the call-site.
Either way, looking at the byte-code will not tell you anything about that. what you could look at is the bootstrap method that invokedynamic
will use : LambdaMetafactory::metafactory
and understand what that will do.