在当前的实现中,生成的类(甚至是非捕获 lambda 表达式的实例)的缓存是invokedynamic https://docs.oracle.com/javase/specs/jvms/se8/html/jvms-6.html#jvms-6.5.invokedynamic指令将重用第一次执行时完成的引导结果。
引导方法本身,托管在LambdaMetafactory https://docs.oracle.com/javase/8/docs/api/?java/lang/invoke/LambdaMetafactory.htmlclass每次被调用都会生成一个新的类。因此,当您直接使用这个工厂时,您将在当前实现下的每次调用中获得一个新类。
public <In, Out, A> BiFunction<In, Out, Out> weave(
Function<? super In, A> getter,
BiConsumer<? super Out, ? super A> consumer) {
MethodHandles.Lookup l = MethodHandles.lookup();
try {
MethodHandle target = l.findStatic(l.lookupClass(), "weaveLambdaBody",
MethodType.methodType(Object.class, Function.class, BiConsumer.class,
Object.class, Object.class));
MethodType t = target.type().dropParameterTypes(0, 2);
return (BiFunction<In, Out, Out>)LambdaMetafactory.metafactory(l, "apply",
target.type().dropParameterTypes(2, 4).changeReturnType(BiFunction.class),
t, target, t) .getTarget().invokeExact(getter, consumer);
}
catch(RuntimeException | Error e) {
throw e;
}
catch(Throwable t) {
throw new IllegalStateException(t);
}
}
private static <In, Out, A> Out weaveLambdaBody(
Function<? super In, A> getter,
BiConsumer<? super Out, ? super A> consumer,
In in, Out out) {
consumer.accept(out, getter.apply(in));
return out;
}
首先,您必须将 lambda 主体脱糖为方法。捕获的值首先出现在其参数列表中,然后是功能接口类型的参数。这LambdaMetafactory https://docs.oracle.com/javase/8/docs/api/?java/lang/invoke/LambdaMetafactory.html有关于其用法的详尽文档。
虽然我出于文档目的保留了类型参数,但很明显,通过这样的操作,您会失去编译时安全性。