java - Lambda Metafactory Variable Capture -
when creating lambda manually using methodhandles.lookup, methodhandles, methodtypes, etc, how might 1 implement variable capture?
for example, no capture:
public intsupplier foo() { return this::fortytwo; } /** * not virtual, oh well. */ public int fortytwo() { return 42; } and clunkier form, using stuff in java.lang.invoke:
public intsupplier foo() { methodhandles.lookup lookup = methodhandles.lookup(); methodtype methodtype = methodtype.methodtype(int.class), lambdatype = methodtype.methodtype(intsupplier.class); methodhandle methodhandle = lookup.findvirtual(getclass(), "fortytwo", methodtype); callsite callsite = lambdametafactory.metafactory(lookup, "getasint", lambdatype, methodtype, methodhandle, methodtype); return (intsupplier) callsite.gettarget().invokeexact(); } /** * not virtual, oh well. */ public int fortytwo() { return 42; } would return simple, pointless intsupplier returns 42 when invoked, if 1 capture something?
the third argument bootstrap method, named lambdatype, invoked type of associated invokedynamic instruction (normally filled in jvm). it’s semantic defined bootstrap method , in case of lambdametafactory, specifies functional interface return type (the type of object construct) , values capture parameter type (the type of values consume when constructing lambda instance).
so in order capture this, have add type of this invoked type , pass this argument invokeexact call:
public class test { public static void main(string... arg) throws throwable { system.out.println(new test().foo().getasint()); } public intsupplier foo() throws throwable { methodhandles.lookup lookup = methodhandles.lookup(); methodtype methodtype = methodtype.methodtype(int.class), invokedtype = methodtype.methodtype(intsupplier.class, test.class); methodhandle methodhandle = lookup.findvirtual(getclass(), "fortytwo", methodtype); callsite callsite = lambdametafactory.metafactory(lookup, "getasint", invokedtype, methodtype, methodhandle, methodtype); return (intsupplier) callsite.gettarget().invokeexact(this); } public int fortytwo() { return 42; } } if want capture more values, have add them signature in right order. e.g., capture int value:
public class test { public static void main(string... arg) throws throwable { system.out.println(new test().foo(100).getasint()); } public intsupplier foo(int capture) throws throwable { methodhandles.lookup lookup = methodhandles.lookup(); methodtype methodtype = methodtype.methodtype(int.class, int.class), functiontype = methodtype.methodtype(int.class), invokedtype = methodtype.methodtype(intsupplier.class, test.class, int.class); methodhandle methodhandle=lookup.findvirtual(getclass(),"addfortytwo",methodtype); callsite callsite = lambdametafactory.metafactory(lookup, "getasint", invokedtype, functiontype, methodhandle, functiontype); return (intsupplier) callsite.gettarget().invokeexact(this, capture); } public int addfortytwo(int valuetoadd) { return 42+valuetoadd; } } the target method have signature consisting of this type, if not static, followed parameter types. capture values map in order signature’s types left right , remaining parameter types, if any, contribute functional signature, hence have match interface method’s parameter types.
this implies when there no captured values , target method not static, method receiver type might become associated first type of functional signature, in tointfunction<string> f=string::length;.
Comments
Post a Comment