📜  Java - 带示例的 Lambda 表达式变量捕获

📅  最后修改于: 2022-05-13 01:54:36.974000             🧑  作者: Mango

Java - 带示例的 Lambda 表达式变量捕获

由 lambda 表达式的封闭范围定义的变量可在 lambda 表达式中访问。例如,lambda 表达式可以使用由其封闭类定义的实例或静态变量。 lambda 表达式还可以访问(显式和隐式),它指的是 lambda 表达式的封闭类的调用实例。因此,lambda 表达式可以获取或设置内在或静态变量的值,并调用由其封闭类定义的方法。

Java的Lambda表达式使用局部变量如上所述。

但是,当 lambda 表达式使用其封闭范围内的局部变量时,会创建一种称为变量捕获的特殊情况。在这种情况下,一个 lambda 表达式可能只使用有效最终的局部变量。一个有效的最终变量是一个在第一次赋值后其值不会改变的变量。无需将此类变量显式声明为 final,尽管这样做不会出错。

重要的是要了解封闭范围的局部变量不能被 lambda 表达式修改。这样做将取消其有效的最终状态,从而使其非法捕获。

有一些关键点需要记住,如下所示:



  1. 任何使用但未在 lambda 表达式中声明的局部变量、形式参数或异常参数必须声明为 final 或有效 final ,否则在尝试使用时会发生编译时错误。
  2. 任何在 lambda 体中使用但未声明的局部变量必须在 lambda 体之前明确赋值,否则会发生编译时错误。
  3. 类似的变量使用规则适用于内部类的主体。对有效最终变量的限制禁止访问动态变化的局部变量,其捕获可能会引入并发问题。相较于最终限制,它减轻了程序员的文书负担。
  4. 对有效最终变量的限制包括标准循环变量,但不包括增强型 for 循环变量,它们在循环的每次迭代中都被视为不同的。

以下程序说明了有效的最终变量和可变局部变量之间的区别:

示例 1

Java
// Java Program Illustrating Difference between
// Effectively final and Mutable Local Variables
  
// Importing reqiored classes
import java.io.*;
// An example of capturing a local variable from the
// enclosing scope
  
// Inrterface
interface MyFunction {
  
    // Method inside the interface
    int func(int n);
}
  
// Main class
class GFG {
  
    // Main driver method
    public static void main(String[] args)
    {
  
        // Custom local variable that can be captured
        int number = 10;
  
        MyFunction myLambda = (n) ->
        {
  
            // This use of number is OK It does not modify
            // num
            int value = number + n;
  
            // However, the following is illegal because it
            // attempts to modify the value of number
  
            // number++;
            return value;
        };
  
        // The following line would also cause an error,
        // because it would remove the effectively final
        // status from num. number = 9;
  
        System.out.println("GFG!");
    }
}


Java
// Java Program Illustrating Difference between
// Effectively final and Mutable Local Variables
  
// Importing input output classes
import java.io.*;
  
// Interface
interface MyInterface {
  
    // Method inside the interface
    void myFunction();
}
  
// Main class
class GFG {
  
    // Custom initialization
    int data = 170;
  
    // Main driver method
    public static void main(String[] args)
    {
  
        // Creating object of this class
        // inside the main() method
        GFG gfg = new GFG();
  
        // Creating object of interface
        // inside the main() method
        MyInterface intFace = () ->
        {
            System.out.println("Data : " + gfg.data);
            gfg.data += 500;
  
            System.out.println("Data : " + gfg.data);
        };
  
        intFace.myFunction();
        gfg.data += 200;
  
        System.out.println("Data : " + gfg.data);
    }
}


输出
GFG!

输出说明:

正如注释所示, number 是有效的 final,因此可以在 myLambda 中使用。但是,如果要修改 number,无论是在 lambda 内部还是外部,number 都会失去其有效的最终状态。这将导致错误,并且程序将无法编译。

示例 2

Java

// Java Program Illustrating Difference between
// Effectively final and Mutable Local Variables
  
// Importing input output classes
import java.io.*;
  
// Interface
interface MyInterface {
  
    // Method inside the interface
    void myFunction();
}
  
// Main class
class GFG {
  
    // Custom initialization
    int data = 170;
  
    // Main driver method
    public static void main(String[] args)
    {
  
        // Creating object of this class
        // inside the main() method
        GFG gfg = new GFG();
  
        // Creating object of interface
        // inside the main() method
        MyInterface intFace = () ->
        {
            System.out.println("Data : " + gfg.data);
            gfg.data += 500;
  
            System.out.println("Data : " + gfg.data);
        };
  
        intFace.myFunction();
        gfg.data += 200;
  
        System.out.println("Data : " + gfg.data);
    }
}
输出
Data : 170
Data : 670
Data : 870