14.1.4 词法作用域
在编写lambda表达式的方法体时,需要注意的是方法体中声明的变量与包含该lambda表达式的上下文环境之间的关系。在这方面,lambda表达式采用了一种简单的实现方式:lambda表达式的方法体并没有引入新的作用域。方法体中的名称与表达式外部的代码处于同一个词法作用域中。在进行解析时,相当于方法体中的名称出现在表达式外部的代码中。而lambda表达式的形式参数也是属于表达式外部代码的名称。
代码清单14-5中的代码会出现编译错误。这是因为变量str在lambda表达式外部的代码中已经被定义了,在lambda表达式的方法体中又被重新定义了一次。由于这两个同名变量存在于同一个词法作用域中,因此编译器不允许多次声明该变量。
代码清单14-5 lambda表达式方法体与外部代码的名称重复的示例
String str="Hello";
new Thread(()->{
String str="World";
System.out.println(str);
}).start();
lambda表达式的这个特性对this变量也适用。对于lambda表达式方法体中出现的this变量,其值相当于this出现在表达式外部的代码中时应该具有的值。这点不同于匿名内部类。由于方法体中this变量的这个特性,方法体中的this变量无法用来引用lambda表达式所表示的对象本身。在某些递归方式的实现中,需要在方法体的代码中引用当前lambda表达式的对象。代码清单14-6给出了一个示例,其中的lambda表达式所表示的对象被赋值给变量task,并在方法体中引用了这个变量。
代码清单14-6 在lambda表达式的方法体中引用表达式所表示的对象
boolean done=false;
List<Runnable>taskQueue=new ArrayList<>();
final Runnable task=()->{
if(!done){
taskQueue.add(task);
}
else{
//任务完成
}
};