Java Closures

2025年5月2日 | 阅读 5 分钟

到目前为止,我们主要关注 Java 中的对象。自 Java 8 以来,编程的函数式方面受到了越来越多的重视。JavaSoft 的人意识到,仅仅使用对象来完成所有事情变得很麻烦,而在某些情况下使用函数会更有效率。Java 8 中的 Lambda 表达式 是最重要的特性,它为 Java 编程方式带来了革命性的变化。在本节中,我们将讨论 Lambda 表达式中的闭包,其声明、实现示例。在深入探讨Java 闭包之前,让我们先了解 Java 中的 Lambda 表达式。

Lambda 表达式

Lambda 表达式是没有名称、访问修饰符和返回类型声明的方法。这类方法被称为匿名方法闭包。它基本上代表了函数式接口的实例。请记住,匿名类是没有名称但可以为其创建对象的类。同样,Lambda 表达式是没有名称但可以用于执行任务的方法。我们也可以将其定义为参数。

为了理解 Lambda 表达式的概念,请考虑以下方法。

要将上述方法转换为 Lambda 表达式,我们将删除访问修饰符 public、返回类型 void、方法名称 show。然后按原样编写方法。

注意空括号。它们表示该方法没有任何参数。之后,我们使用了箭头符号 (->),它将方法头与方法体分隔开。我们也可以在一行中写出上述 Lambda 表达式。

假设我们要通过 Lambda 表达式执行两个数字的和。该操作的 Lambda 表达式将是:

Lambda 表达式分为两类。

  • 开放表达式 (OPEN Expression): 在此表达式中,某些符号未绑定。这意味着其中出现的某些符号是自由的,并且需要一些外部信息。
  • 闭合表达式 (CLOSED Expression): 它们是自包含的表达式。这意味着它们不需要任何外部上下文即可进行求值。它也称为组合子。

闭包

闭包是(或方法)在 其词法上下文 中引用自由变量函数。函数是带有参数的代码块。它可能会产生一个结果值(返回类型)。自由变量是闭包使用但未定义的标识符。它可以在不作为方法或类的情况下使用。这意味着闭包可以访问参数列表中未定义的变量,也可以分配给变量。我们也可以将闭包作为参数传递。

换句话说,当 Lambda 表达式能够访问其作用域之外的变量时,它就变成了闭包。这意味着 Lambda 可以访问其外部作用域。

注意:Java 不支持闭包。

目标

闭包的主要目标是简洁地表示函数字面量,而无需处理匿名实例的麻烦,并与现有 API 进行互操作。我们还可以使用 Java 闭包执行函数式和聚合操作。它有助于保护数据并提供柯里化。

声明

Java 闭包的声明与 Lambda 表达式相同。如果我们想在 Java 中声明闭包,应使用以下语法。

语法

Java 闭包示例

让我们通过一个 Java 程序来理解 Lambda 表达式中的闭包。首先,我们将创建一个名为 Operation 的接口。

Operation.java

让我们运行上述 Java 程序。

输出

Sum is: 110

现在,我们将尝试在 operate() 方法中更改 y 的值。看看会发生什么。

对程序进行上述更改后,再次编译并运行。它会显示编译错误。

Java Closure

请注意,我们没有将变量 y 声明为 final,但编译器仍将其视为 final 变量(final int y=90;)。因此,这个概念在JDK 1.8 中已有所改变。

让我们使用 JDK 1.7 运行上述程序。要更改 Eclipse IDE 中的编译器,请按照以下步骤操作。

  • 右键单击您创建的项目。
  • 单击底部的属性 (Properties) 菜单,或按 Alt + Enter
  • 单击左窗格中显示的Java 编译器 (Java compiler) 选项。
    Java Closure
  • 取消选中JDK 合规性 (JDK Compliance) 下的选项。
    Java Closure
  • 编译器合规性 (Compiler compliance) 级别更改为7
    Java Closure
  • 之后,单击应用并关闭 (Apply and Close) 按钮。

再次运行上述程序。它显示以下编译错误。

Java Closure

为了运行程序,将变量 y 设置为 final。

之后,再次运行程序。

输出

Sum is: 110

因此,在 Java 8 中,我们不需要将变量设置为 final。Java 编译器会自动将其视为 final 变量。这个概念在 Lambda 表达式中称为闭包

让我们使用 Lambda 表达式编写上述程序。

ClosureExample.java

输出

110

闭包与 Lambda 的区别

Java Lambda 表达式是一种内联定义函数的方式,而不是标准的方法声明。它提供了一种简洁的方式来表示函数。而闭包是一个函数,它通过引用其主体外部的字段来包含其周围的状态。请注意,两者都是函数,但并非所有闭包都是 Lambda,也并非所有 Lambda 都是闭包

闭包和 Lambda 之间的区别与类和类的实例之间的区别相当。类只存在于源代码中。它在运行时不存在。在运行时存在的是类的对象。闭包之于 Lambda,如同对象之于类。下表描述了闭包和 Lambda 之间的主要区别。