【发布时间】:2019-09-19 02:11:00
【问题描述】:
Java 规范保证给定的 lamda 定义,例如() -> "Hello World",被编译/转换为一个实现类(每个定义,不是每个“看起来”相同的出现)。
有什么办法可以强制 java-compiler/jvm 生成一个新的 lamda-definition 而不是共享一个通用的?我目前正在实现一个库,该库将多个函数部分编织到 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;
};
}
通过此代码生成的每个 lamda 共享相同的 lamda-definition,因此大多是不可内联/不可优化的。
【问题讨论】:
-
如果没有运行时代码生成,您似乎没有运气。
-
存在一个基本的误解。规范中没有任何内容可以保证这一点。规范允许产生相同的实现类,但实际上,它明确表示相同的lambda表达式可能导致不同的实现类。
-
“不同的 lambda 表达式产生的对象不必属于不同的类”表示允许不同的 lambda 表达式产生同一个类(这在今天的参考实现)。下一点说“评估产生的每个对象都不必属于同一个类(例如,捕获的局部变量可能是内联的)。”这正是您的场景。相同的 lambda 表达式可能被评估为不同类的实例(这在今天的参考实现中也不会发生)。
-
@talex 每个
BiFunction实例只捕获一个BiConsumer实例,总是以相同的实现结束。如果您为每个BiFunction实例生成一个不同的类,这将是一个完美的单态行为。但我认为这不是必需的,因为 JVM 可能会通过多个调用级别将函数代码内联到不同的专用版本中。关键是这里抓到的BiConsumer实例。也许,指定-XX:+TrustFinalNonStaticFields可以在这里有所作为。 -
@talex 是的,JIT 能够内联方法调用,不管这个方法的类是如何生成的。实际上,静态 lambda 表达式是使用相同的
LambdaMetafactory实例化的。