如何强制执行lamda定义的新实例 [英] How to force a new instantiation of a lamda-definition

查看:71
本文介绍了如何强制执行lamda定义的新实例的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

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

The Java-Spec guarantees that a given lamda-definition, e.g. () -> "Hello World", is compiled/converted to exactly one implementation class (every definition, not every occurence that "looks" the same).

有什么办法可以强制java-compiler/jvm生成新的lamda定义,而不是共享一个通用的lamda定义?我目前正在实现一个将多个功能部件编织到BiFunction中的库,该库由于Java-spec( 我已得到纠正:Java-Spec不保证单个共享类-当前的参考实现可以做到这一点):

Is there any way I can force the java-compiler/jvm to generate a new lamda-definition instead of sharing a common one? I am currently implementing a library that weaves multiple function parts into a BiFunction which suffers from mega-morphic call-sites because of the guarantees given by the java-spec ( I stand corrected: the Java-Spec does not guarantee a single shared class - the current reference implementation does this though):

        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;
            };
        }

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

Every lamda generated through this code shares the same lamda-definition and is thus mostly uninlineable / unoptimizeable.

推荐答案

在当前实现中,生成类的缓存(甚至非捕获lambda表达式的实例)是

In the current implementation, the caching of generated classes (or even instances for the non capturing lambda expressions), is a property of the invokedynamic instruction which will reuse the result of the bootstrapping done on the first execution.

bootstrap方法本身,位于

The bootstrap method itself, hosted in the LambdaMetafactory class will generate a new class each time it is invoked. So when you use this factory directly, you’ll get a new class on each invocation, under the current implementation.

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 具有有关其用法的详尽文档.

First, you have to desugar the lambda body into a method. The captured values come first in its parameter list, followed by the parameters of the functional interface type. The LambdaMetafactory has an exhaustive documentation about its usage.

虽然我出于文档目的保留类型参数,但应该清楚的是,使用这种操作会失去此处的编译时安全性.

While I kept the type parameters for documentation purposes, it should be clear that you lose the compile-time safety here, with such an operation.

这篇关于如何强制执行lamda定义的新实例的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆