java - 如何强制 lambda 定义的新实例化

标签 java jvm inlining

Java 规范保证给定的 lambda 定义,例如() -> "Hello World",被编译/转换为一个实现类(每个定义,而不是每个“看起来”相同的事件)。

有什么方法可以强制 java 编译器/jvm 生成一个新的 lambda 定义而不是共享一个通用的定义?我目前正在实现一个库,该库将多个函数部分编织到一个 BiFunction 中,由于 java-spec 提供的保证,它会受到巨型调用站点的影响(编辑:我纠正了:Java-Spec 不保证单个共享类 - 尽管当前的引用实现是这样做的):

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

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

最佳答案

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

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

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 主体脱糖到方法中。捕获的值在其参数列表中排在第一位,然后是功能接口(interface)类型的参数。 LambdaMetafactory有关于其用法的详尽文档。

虽然出于文档目的我保留了类型参数,但应该清楚的是,通过这样的操作,您在这里失去了编译时安全性。

关于java - 如何强制 lambda 定义的新实例化,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/55920520/

相关文章:

c++函数指针内联

java - Hadoop在程序中的映射器中输入数据,而不是文件中的数据

java - azure java SDK交互式登录支持

jvm - JVM 或 CLR 是否使用寄存器来运行 JIT 代码?

java - java数组是如何真正工作的

c - 抑制内联警告

java - Java中的方法重写-将子类对象分配给父类变量

java - 我可以使用 web.xml 设置 Jersey 客户端的配置吗

Java 调用堆栈检查和操作

c - 内联函数