java - Java 8 lambda 是否被编译为内部类、方法或其他东西?

标签 java lambda java-8

<分区>

我今天读了这篇关于 lambda 的文章:

http://www.infoq.com/articles/Java-8-Lambdas-A-Peek-Under-the-Hood

文章建议,lambdas 没有实现为匿名内部类(由于性能)。 它给出了一个 lambda 表达式可以编译为类的(静态)方法的示例。

我尝试了一个非常简单的片段:

private void run() {
    System.out.println(this);
    giveHello(System.out::println);
}

private void giveHello(Consumer<String> consumer) {
    System.out.println(consumer);
    consumer.accept("hello");
}

输出是:

sample.Main@14ae5a5
sample.Main$$Lambda$1/168423058@4a574795
hello

所以这不是同一个实例。它也不是一些中央“Lambda 工厂”实例..

lambda 是如何实现的?

最佳答案

表达式本身,假设您传递了一个实际的 lambda 表达式 而不是一个方法引用,被编译为一个单独的合成方法。除了预期功能接口(interface)的任何正式参数(例如,在 String 的情况下为单个 Consumer<String>),它还将包含任何捕获值的参数。

在 lambda 表达式或方法引用出现的代码位置,invokedynamic发出指令。第一次命中此指令时,将调用 LambdaMetafactory 上的 Bootstrap 方法。 .此引导方法将修复目标功能接口(interface)的实际实现,该接口(interface)委托(delegate)给目标方法,这就是返回的内容。目标方法是代表 lambda 主体的合成方法或使用 :: 提供的任何命名方法。运算符(operator)。当一个实现功能接口(interface)的类正在被创建时,这个过程被推迟了;它不会在编译时发生。

最后,运行时修补 invokedynamic带有引导结果1 的站点,它实际上是对生成的委托(delegate)的构造函数调用,其中传递了任何捕获的值,包括(可能)调用目标2。这通过删除后续调用的引导过程来减轻性能影响。


1 参见 java.lang.invoke end of chapter "timing of linkage" ,由@Holger 提供。

2 对于没有捕获的 lambda,invokedynamic指令通常会解析为可在后续调用期间重复使用的共享委托(delegate)实例,尽管这是一个实现细节。

关于java - Java 8 lambda 是否被编译为内部类、方法或其他东西?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/26257266/

相关文章:

java - 光线转换未报告碰撞

java - Boids 中的矩形避免

Java Lambda 表达式

java - 为什么 LocalDateTime 没有 String 构造函数?

java - 按属性对对象列表进行分组并将其他剩余属性设置为不同的对象列表 : Java 8 stream and Lambdas

Java - JTabbedPane - 添加新面板时出现 ArrayIndexOutOfBoundsException

java - 从 jsp 检索更新的数组列表到 struts2 中的 Action 类

linq - 评估 lambda 表达式

python - 在python中的两个最小键之间进行选择

java - 扩展 RepositoryRestMvcConfiguration 打破了 Jackson LocalDateTime 序列化