MST

星途 面试题库

面试题:Java Lambda表达式的作用域和闭包问题

在Java Lambda表达式中,阐述其作用域规则以及闭包是如何工作的。如果Lambda表达式访问外部局部变量,需要注意什么?请举例分析说明。
43.2万 热度难度
编程语言Java

知识考点

AI 面试

面试题答案

一键面试

Lambda表达式作用域规则

  1. 与匿名类类似:Lambda表达式的作用域与匿名类的作用域类似。它可以访问外部类的成员变量(包括私有成员变量),也可以访问其所在方法中的局部变量,但对局部变量有特殊要求。
  2. 局部变量的作用域:在Lambda表达式内部可以访问外部方法中的局部变量,但是这些局部变量必须是事实上的final。这意味着一旦给局部变量赋值,就不能再重新赋值。

闭包工作原理

  1. 概念:闭包是一个代码块(如Lambda表达式),它可以记住并访问其词法作用域之外的变量,即使在这些变量在其原始作用域结束后仍然存在。
  2. 在Java Lambda中的实现:当Lambda表达式捕获外部变量时,Java会将这些变量的值复制到Lambda表达式的内部表示中。例如,如果在方法中定义一个局部变量并在Lambda中使用它,实际上Lambda使用的是这个变量的一个副本。这个副本的值在Lambda创建时就被确定,并且不会随着外部变量值的改变而改变(因为外部变量是事实上的final)。

访问外部局部变量需注意事项

  1. 事实上的final:如上述所说,外部局部变量必须是事实上的final。如果尝试在Lambda表达式内部修改外部局部变量的值,会导致编译错误。
  2. 生命周期:外部局部变量的生命周期至少要与Lambda表达式的生命周期一样长。如果外部局部变量在Lambda表达式执行之前就已经超出作用域,会导致程序出错。

举例分析

public class LambdaClosureExample {
    public static void main(String[] args) {
        int num = 10;
        // 这里num是事实上的final
        Runnable r = () -> System.out.println("Value of num is: " + num);
        num = 20; // 这行代码会导致编译错误,因为num在Lambda表达式中被使用,不能重新赋值
        r.run();
    }
}

在上述例子中,nummain方法中的局部变量,在Lambda表达式中使用。由于它在Lambda表达式中被捕获,所以不能再对其进行重新赋值,否则会出现编译错误。如果将num声明为final,也能达到同样的效果,并且更清晰地表明该变量不会被修改。