目录
一、什么是变量捕获?
在Java中,变量捕获(Variable Capturing)通常指的是在匿名内部类或Lambda表达式中,引用外部作用域的局部变量。当在一个匿名内部类或Lambda表达式中引用外部作用域的局部变量时,该局部变量会被捕获并保存下来,以便在内部类或Lambda表达式中访问和使用。
二、匿名内部类的变量捕获
class Test {
public void func() {
System.out.println("func()");
}
}
public class TestDemo {
public static void main(String[] args) {
int a = 100;
Test test = new Test() {
@Override
public void func() {
System.out.println("我是内部类,且重写了func这个方法!");
System.out.println("我是捕获到变量 a == " + a
+ " 我是一个常量,或者是一个没有改变过值的变量!");
}
};
test.func();
}
}
在上述代码当中的变量a就是捕获的变量。
可以看到,a=100被正确地捕获了。
重点!被匿名内部类或lambda表达式捕获的变量,要满足一下两种要求之一:
- 这个变量被final修饰。
- 如果这个变量不是被final修饰,要求事实上是最终的,即这个变量在被捕获之后没有被修改。
原因:
- 被Lambda表达式或匿名内部类捕获的局部变量必须在编译时确定其值,并且在捕获之后不能再被修改,以确保在Lambda表达式或匿名内部类中能够安全地访问。
在Java 8之前,如果在匿名内部类或Lambda表达式中引用了外部作用域的局部变量,则这个局部变量必须显式声明为final。从Java 8开始,对于实际上不会发生更改的局部变量,可以省略final关键字,编译器会隐式地将其视为final。
因此,如果一个局部变量被Lambda表达式或匿名内部类捕获,那么它必须满足以上要求。
这些规定是为了保证在Lambda表达式或匿名内部类中能够正确地访问和使用外部作用域的局部变量,并且避免由于多线程等因素导致的并发访问问题。
如下代码就是错误的代码:
class Test {
public void func() {
System.out.println("func()");
}
}
public class TestDemo {
public static void main(String[] args) {
int a = 100;
Test test = new Test() {
@Override
public void func() {
a = 99;
System.out.println("我是内部类,且重写了func这个方法!");
System.out.println("我是捕获到变量 a == " + a
+ " 我是一个常量,或者是一个没有改变过值的变量!");
}
};
test.func();
}
}
可以看到a在匿名内部类中又被修改了,该代码直接编译报错。
三、Lambda表达式的变量捕获
@FunctionalInterface
interface NoParameterNoReturn {
void test();
}
public class TestDemo {
public static void main(String[] args) {
int a = 10;
NoParameterNoReturn noParameterNoReturn = () -> {
a = 99; //error
System.out.println("捕获变量:" + a);
};
noParameterNoReturn.test();
}
}
同样的,如果在Lambda重写test方法中,尝试修改了外部变量 a 的值,此时会和匿名内部类一样编译报错。
四、变量捕获机制的好处
变量捕获机制主要有以下几个方面的好处:
-
简化代码逻辑:通过变量捕获机制,内部类或Lambda表达式可以访问外部作用域的变量,避免了需要额外传递参数的繁琐过程,使得代码逻辑更为简洁明了。
-
提高代码可读性:将相关的变量直接捕获到内部类或Lambda表达式中,使得代码的依赖关系更加清晰,提高了代码的可读性和可维护性。
-
减少重复代码:通过变量捕获机制,可以避免在内部类或Lambda表达式中重复定义外部作用域的变量,减少了代码冗余,使代码更为简洁。
-
保证数据一致性:变量捕获机制要求外部作用域的局部变量是 final 或 effectively final 的,这种限制确保了在多线程环境下数据的一致性,避免了潜在的并发问题。
-
提升代码可靠性:由于变量捕获机制的限制,能够在编译阶段检查变量的赋值情况,减少了出错的可能性,从而提高了代码的可靠性。
综上所述,变量捕获机制能够使代码更加清晰、可靠和优雅,帮助开发人员编写出结构清晰、易读易懂的代码,提高代码质量和开发效率。