Java Lambda表达式中的变量范围
在本文中,我们将看到Java的lambda表达式中变量的范围是什么。这个主题很重要,因为它涉及到Java 8中增加的一个概念。在Java中最终有效。
Java Lambda表达式变量范围
Java中的Lambda表达式没有自己的范围,它的范围与其封闭的范围相同。如果在lambda表达式中定义的变量与其封闭范围中的变量具有相同的名称,则会导致错误。
例如
String s1 = "Lambda"; // Error Comparator<String> comp = (s1, s2) -> s1.length() - s2.length();
该lambda表达式实现了Comparator功能接口的compare()方法,但是由于lambda表达式中使用的参数与已定义的局部变量s1具有相同的名称,因此将导致错误。因此,该语句导致编译时错误" Lambda表达式的参数s1无法重新声明在封闭范围内定义的另一个局部变量"。
访问Lambda表达式中的封闭范围变量
由于lambda表达式不会带来新的作用域范围,因此我们可以直接访问封闭范围的字段,方法和局部变量。但是,如何使用来自封闭范围的变量存在限制。像本地和匿名类一样,lambda表达式只能访问最终或者有效最终的局部变量和封闭范围的参数。
Java中有效的最终变量是一个变量,一旦分配其值便无法对其进行修改。因此,任何包含范围的变量都可以声明为final,或者默认情况下实际上是final,并且不能在lambda表达式或者内部类中进行修改。实际上,在Java 8之前,必须将这样的字段(在内部类中使用)定义为final,而从Java 8开始,它需要放宽一点,并且不需要将此类字段显式声明为final。
@FunctionalInterface interface TestInterface{ int calculate(int i, int j); } public class LambdaExample { public static void main(String[] args) { int num = 7; TestInterface ref = (x, y) -> { // Modifying value of enclosing scope field num = x + y; return num; }; } }
在上面的示例中,在lambda表达式块中,尝试从封闭范围中修改变量的值,这会导致错误"在封闭范围中定义的局部变量num必须是最终的或者有效地是最终的"。
为什么有效地最终
现在出现了一个问题,为什么对包围范围变量进行这样的限制。使用来自封闭范围的变量的lambda表达式捕获此类变量的值。由于Java中的lambda表达式是功能接口的实例,因此在该实例中使用的包围范围的字段会捕获并使用这些字段的值。保持这些字段的状态很重要,这样就不会对其进行修改,这就是为什么要限制"有效最终"的原因。
在lambda表达式中使用this和super关键字
由于lambda表达式不会引入新的作用域,因此在lambda中将此关键字和super关键字一起使用时,将引用调用了lambda表达式所驻留的方法的同一对象。
@FunctionalInterface interface TestInterface{ int calculate(int i, int j); } class Test { public void showValue(String str) { System.out.println("Value is- " + str); } } public class LambdaExample extends Test{ public static void main(String[] args) { LambdaExample obj = new LambdaExample(); obj.getResult(); } public void getResult(){ TestInterface ref = (x, y) -> { // Modifying value of enclosing scope field System.out.println("ToString- " + this.toString()); super.showValue("Calling from Lambda"); return x+y; }; System.out.println("Result is- " + ref.calculate(8, 6)); } }
输出:
ToString- Hyman@theitroad Value is- Calling from Lambda Result is- 14
在示例中,LambdaExample类扩展了Test类,并具有方法getResult(),其中我们具有lambda表达式。如我们所见,lambda表达式可以访问this和super。从lambda调用this.toString()会打印LambdaExample的实例,而不是TestInterface的实例。