面试题答案
一键面试Lambda表达式作用域规则
- 与匿名类类似:Lambda表达式的作用域与匿名类的作用域类似。它可以访问外部类的成员变量(包括私有成员变量),也可以访问其所在方法中的局部变量,但对局部变量有特殊要求。
- 局部变量的作用域:在Lambda表达式内部可以访问外部方法中的局部变量,但是这些局部变量必须是事实上的final。这意味着一旦给局部变量赋值,就不能再重新赋值。
闭包工作原理
- 概念:闭包是一个代码块(如Lambda表达式),它可以记住并访问其词法作用域之外的变量,即使在这些变量在其原始作用域结束后仍然存在。
- 在Java Lambda中的实现:当Lambda表达式捕获外部变量时,Java会将这些变量的值复制到Lambda表达式的内部表示中。例如,如果在方法中定义一个局部变量并在Lambda中使用它,实际上Lambda使用的是这个变量的一个副本。这个副本的值在Lambda创建时就被确定,并且不会随着外部变量值的改变而改变(因为外部变量是事实上的final)。
访问外部局部变量需注意事项
- 事实上的final:如上述所说,外部局部变量必须是事实上的final。如果尝试在Lambda表达式内部修改外部局部变量的值,会导致编译错误。
- 生命周期:外部局部变量的生命周期至少要与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();
}
}
在上述例子中,num
是main
方法中的局部变量,在Lambda表达式中使用。由于它在Lambda表达式中被捕获,所以不能再对其进行重新赋值,否则会出现编译错误。如果将num
声明为final
,也能达到同样的效果,并且更清晰地表明该变量不会被修改。