跳到主要内容

JEP 126:Lambda 表达式和虚拟扩展方法

概括

将 lambda 表达式(闭包)和支持功能(包括方法引用、增强类型推断和虚拟扩展方法)添加到 Java 编程语言和平台。

目标

lambda 表达式和虚拟扩展方法的主要功能及其辅助支持功能集进一步实现了几个平台目标:

  • 简化更抽象、更高性能库的创建和使用
  • 通过迁移兼容性支持更平滑的库演进

除了向 Java 编程语言添加现在常见的功能之外,lambda 表达式还通过启用内部迭代惯用语开辟了改进多核支持的可能性。

围绕 lambda 的支持语言功能包括_虚拟扩展方法_,这将允许接口以源代码和二进制兼容的方式发展。

除了语言变化之外,协调库和 JVM 也会发生变化。

请注意,活跃且正在进行的Project Lambda OpenJDK 项目早于 JEP 流程,相应的 JSR JSR 335也是如此,它针对的是 Java SE 8 ( JSR 336 )。

非目标

函数类型和通用控制抽象的语言特性并不是_在_Java 中添加 lambda 表达式的目标。然而,我们的目的是不排除将来添加此类功能。

动机

许多其他常用的面向对象编程语言,包括托管在 JVM 上的语言(例如 Groovy、Ruby 和 Scala)和托管在其他虚拟机上的语言(CLR 上的 C#),都支持闭包。因此,Java 程序员越来越熟悉该语言特性及其支持的编程模型。

特别令人感兴趣的是启用内部迭代_的习惯用法。数组和集合当前支持_外部迭代,其中迭代的控制逻辑位于正在遍历的数据结构之外。例如,for对数组或集合的 -each 循环就是外部迭代的一个示例。 Java 中循环的语义for要求严格的串行迭代,这意味着程序员迭代标准集合的唯一方法将不允许使用所有可用的内核。

通过内部迭代,数据结构会以 lambda 表达式的形式传递一段代码来执行,数据结构负责划分计算并报告结果。由于数据结构熟悉其自身的内部细节,因此它可以通过调整选项来选择更好的计算调度,例如

  • 备用执行顺序
  • 使用线程池并发执行
  • 使用分区和工作窃取的并行执行。 Java SE 7 中添加的fork/join 框架就是这样一种候选并行执行框架,它在各种核心数量上提供性能稳健的工作分区。

内部迭代风格的一个典型示例是一系列过滤-映射-归约操作,例如:

int maxFooWeight =
collection.filter( /* isFoo Predicate as a lambda */)
.map( /* Map a Foo to its weight with a lambda */)
.max(); /* Reduction step */

lambda 表达式是具有简洁语法的表达式,用于表示所需的操作。这种风格代替了一个或多个显式for循环,这将不必要地限制集合上的迭代顺序。此外,精心设计的算法不仅可以并行执行这些操作集,还可以将这三个操作聚合到单个并行通道中。

Lambda 项目还包括虚拟扩展方法,这将解决由于源兼容性问题而无法向广泛使用的接口添加方法的长期限制。

通过向现有集合接口(例如java.util.Collectionjava.util.List)添加扩展方法,这些类型的现有实现可以参与新的编程习惯。 JDK(和其他地方)中这些类型的实现可以覆盖超级接口中扩展方法的默认实现,以提供更高的性能或其他专门的实现。

描述

正在进行的Lambda 项目相应 JSR 的OpenJDK 项目页面提供了有关该工作细节的最新信息。

受整个 Lambda 项目工作影响的平台组件包括:

  • Java 编程语言规范
  • Java虚拟机的规范
  • 语言变化的参考实现javac
  • 类文件更改以支持 lambda 表达式和虚拟扩展方法的编译
  • (可能)JVM 增强功能可改善 lambda 的执行
  • JVM 进行更改以支持虚拟扩展方法
  • 核心 API 更改以添加虚拟扩展方法
  • 核心 API 更改以支持 lambda 表达式的使用
  • 更新 JDK 库以使用新的扩展方法
  • 更新反射 API,例如核心反射和javax.lang.model,以公开 lambda 和扩展方法相关信息
  • 更新类文件工具,例如javappack200/unpack200以了解新的 JVM 属性
  • (可能的)序列化更新,包括 IIOP 序列化
  • 增强 javadoc 以指示哪些接口可用于 lambda
  • 语言运行时java.lang.*支持 lambda 表达式和虚拟扩展方法的转换

备择方案

Lambda 项目始于一个稻草人提案,并经历了多次“Lambda 状态”迭代,这些迭代已经发展了该项目的语法和功能集。

Lambda 项目的 lambda 表达式部分的工作得益于之前的大量工作,包括但不限于:

Lambda 项目的功能集被认为比早期提案更好地满足了 Java 平台发展的需求。

虚拟扩展方法的设计同样受到编程语言社区中大量先前工作的启发,包括:

与其他语言环境相比,Java 语言始终具有更_可预测的_语义、内置基元类型的大小已知、在精确位置引发异常、精确定义表达式的执行顺序等等。放松内置forwhile循环的语义以允许自动并行化尝试被认为既不理想,也不足以满足支持多核的目标。

测试

除了单元/回归测试之外,还将开发 JCK 测试作为新的语言功能。

该功能的实用性还将通过 JDK 平台库中的使用进行验证。

风险和假设

由于涉及平台许多方面的巨大努力,有可能出现不可预见的复杂性和交互。

通过尽早开始并计划多次迭代(例如支持库工作),应该减轻这些复杂性的影响。

依赖关系

当前首选的 lambda 表达式实现方法依赖于JSR 292invokedynamic引入的方法句柄。因此,lambda 可接受的性能取决于方法句柄的可接受性能以及其他因素。

预计库工作(JEP 107 和 109)和语言功能之间会有反馈。

影响

  • 其他 JDK 组件:描述部分概述了其他 JDK 组件的影响。
  • 兼容性:虚拟扩展方法旨在允许接口的源兼容演进。添加虚拟扩展方法
  • 安全性:需要对 lambda 的运行时实现进行安全审查。
  • 性能/可扩展性:应该跟踪 lambda 友好惯用法与传统惯用法的性能。
  • 文档:需要编写用户指南和支持文档。
  • TCK:作为一个大的平台特性,需要开发语言和库TCK。