如何使用LambdaMetafactory.metafactory为静态方法生成捕获int参数的Lambda表达式
如何使用LambdaMetafactory.metafactory为静态方法生成捕获int参数的Lambda表达式
最近我在折腾用LambdaMetafactory.metafactory动态生成Lambda表达式,需求是调用一个静态方法,而且这个Lambda得额外捕获一个int类型的参数——相信不少朋友也遇到过类似的场景,今天就来一步步说清楚怎么实现。
上下文
先把基础的东西摆出来,方便大家理解场景:
首先是我们要使用的函数式接口:
@FunctionalInterface public interface Binder { void parseAndStore(byte[] src, byte[] dst); }
然后是我们要调用的目标静态方法(这里补全合理的实现方便演示):
public class StaticMethods { public static void parseWithCapturedInt(int capturedValue, byte[] src, byte[] dst) { // 这里可以写你的业务逻辑,比如用捕获的int值处理src和dst System.out.println("捕获的int参数值:" + capturedValue); // 其他业务操作... } }
实现步骤
1. 理解核心逻辑
我们要做的其实是:把捕获的int参数提前绑定到静态方法的第一个参数上,让绑定后的方法句柄签名和Binder接口的parseAndStore方法完全匹配,这样LambdaMetafactory就能基于这个绑定后的句柄生成符合要求的Lambda。
2. 编写动态生成Lambda的代码
直接上可运行的代码示例,每一步都加了注释:
import java.lang.invoke.*; import java.lang.reflect.Method; public class LambdaGenerator { public static Binder createBinder(int capturedInt) throws Throwable { // 第一步:获取目标静态方法的MethodHandle Method targetMethod = StaticMethods.class.getMethod( "parseWithCapturedInt", int.class, byte[].class, byte[].class ); MethodHandle targetHandle = MethodHandles.lookup().unreflect(targetMethod); // 第二步:把捕获的int参数绑定到方法句柄上 // 绑定后,原来需要三个参数的方法句柄,就变成只需要两个byte[]参数了 MethodHandle boundHandle = targetHandle.bindTo(capturedInt); // 第三步:定义函数式接口的方法类型 MethodType lambdaMethodType = MethodType.methodType(void.class, byte[].class, byte[].class); // 第四步:获取绑定后的方法句柄的类型 MethodType boundMethodType = boundHandle.type(); // 第五步:指定函数式接口要实现的方法名称 String lambdaMethodName = "parseAndStore"; // 第六步:调用LambdaMetafactory生成Lambda实例 CallSite callSite = LambdaMetafactory.metafactory( MethodHandles.lookup(), lambdaMethodName, MethodType.methodType(Binder.class), // 我们要生成的Lambda的类型是Binder lambdaMethodType, // 函数式接口的方法签名 boundHandle, // 已经绑定了捕获参数的目标方法句柄 boundMethodType // 绑定后的方法签名,要和上面的lambdaMethodType匹配 ); // 第七步:获取并返回Lambda实例 return (Binder) callSite.getTarget().invokeExact(); } // 测试用的main方法 public static void main(String[] args) throws Throwable { Binder myBinder = createBinder(42); myBinder.parseAndStore(new byte[0], new byte[0]); } }
3. 关键细节说明
bindTo这个方法太重要了:它能帮我们把固定的参数(也就是要捕获的int)绑定到方法句柄上,相当于“提前填好”静态方法的第一个参数,这样剩下的参数就正好和函数式接口的方法参数对应上了。LambdaMetafactory.metafactory的参数一定要对应对:invokedType参数(第三个)要指定我们最终要生成的Lambda的类型,这里就是Binder.class;samMethodType(第四个)是函数式接口的方法签名,implMethodType(第六个)是绑定后的方法句柄的签名,这两个必须完全匹配,不然会报错。
4. 验证效果
运行上面的main方法,你会看到控制台输出“捕获的int参数值:42”,这说明我们的Lambda不仅成功生成了,还正确捕获并传递了int参数给静态方法,完美达到需求!
备注:内容来源于stack exchange,提问作者Thiru kumaran
相关产品推荐
相关产品推荐

