如何强制执行lamda定义的新实例

roo*_*eee 5 java jvm inlining

Java-Spec保证将给定的lamda定义(例如() -> "Hello World")编译/转换为仅一个实现类(每个定义,并非每个“看起来”都相同的事件)。

有什么方法可以强制java-compiler / jvm生成新的lamda定义,而不是共享一个通用的lamda定义?我目前正在实现一个将多个功能部件编织到BiFunction中的库,该库由于Java-spec提供的保证而遭受了大形调用站点的困扰(编辑:我已纠正:Java-Spec不保证单个共享class-当前的参考实现会执行此操作):

        public <In, Out, A> BiFunction<In, Out, Out> weave(
             Function<? super In, A> getter,
             BiConsumer<? super Out, ? super A> consumer
        ) {
            return (in, out) -> {
                consumer.accept(out, getter.apply(in));
                return out;
            };
        }
Run Code Online (Sandbox Code Playgroud)

通过此代码生成的每个lamda都共享相同的lamda定义,因此大多是不可内联的/不可优化的。

Hol*_*ger 2

在当前实现中,生成的类(甚至非捕获 lambda 表达式的实例)的缓存是指令的一个属性,invokedynamic它将重用第一次执行时完成的引导结果。

\n\n

托管在LambdaMetafactory类中的引导方法本身将在每次调用时生成一个新类。因此,当您直接使用此工厂时,在当前实现下,您\xe2\x80\x99将在每次调用时获得一个新类。

\n\n
public <In, Out, A> BiFunction<In, Out, Out> weave(\n     Function<? super In, A> getter,\n     BiConsumer<? super Out, ? super A> consumer) {\n\n    MethodHandles.Lookup l = MethodHandles.lookup();\n    try {\n        MethodHandle target = l.findStatic(l.lookupClass(), "weaveLambdaBody",\n            MethodType.methodType(Object.class, Function.class, BiConsumer.class,\n                Object.class, Object.class));\n        MethodType t = target.type().dropParameterTypes(0, 2);\n        return (BiFunction<In, Out, Out>)LambdaMetafactory.metafactory(l, "apply",\n            target.type().dropParameterTypes(2, 4).changeReturnType(BiFunction.class),\n            t, target, t) .getTarget().invokeExact(getter, consumer);\n    }\n    catch(RuntimeException | Error e) {\n        throw e;\n    }\n    catch(Throwable t) {\n        throw new IllegalStateException(t);\n    }\n}\nprivate static <In, Out, A> Out weaveLambdaBody(\n    Function<? super In, A> getter,\n    BiConsumer<? super Out, ? super A> consumer,\n    In in, Out out) {\n\n    consumer.accept(out, getter.apply(in));\n    return out;\n}\n
Run Code Online (Sandbox Code Playgroud)\n\n

首先,您必须将 lambda 主体脱糖为方法。捕获的值首先出现在其参数列表中,然后是功能接口类型的参数。有关LambdaMetafactory于其用法的详尽文档。

\n\n

虽然我出于文档目的保留了类型参数,但很明显,通过这样的操作,您会失去编译时安全性。

\n