先来看一下 lambda 表达式长啥样:
xxx ()-> xxx
忽略两个 xxx,关键在于中间的部分。
能访问外部变量吗
能。
能修改吗
也能。
但不是总能,有些情况就不行。
说一下原因:
变量分为 局部变量、实例变量、静态变量 这三种。
后两种合并起来叫 成员变量。
局部变量 就不能修改。
为什么不能?
处于线程安全的考虑,Java做了限制或者说是约束。
如果修改了会怎么样?
看一段代码:
public void test() {
int a = 0;
List<Integer> list = new ArrayList<>();
list.forEach(item -> {
System.out.println(a); // 此行不会报错
a++; // 此行会报错
});
}
行 System.out.println(a); 仅仅是访问,自然是可以的。
行 a++; 修改原值了,那就不行了,编译时就报错。
那为什么修改了会报错?
因为 a 是一个局部变量,存储在栈中,方法运行结束即销毁。
如果 lambda 表达式还没运行完,外面的 test 方法已经运行结束了,此时 a 已无,那就出问题了。
所以实际上调用 a 得到的只是一个值,而非内存地址。
而成员变量不一样,静态变量存储在方法区,实例变量一般存储在堆中,不是说你一个方法结束了就没了,因此可以修改。
我非要修改怎么办
教你个方法,代码改成这样:
AtomicInteger a = new AtomicInteger();
List<Integer> list = new ArrayList<>();
list.forEach(item -> {
a.getAndIncrement();
});
为什么这样就没问题了?
AtomicInteger 是什么东西?
直译过来就是原子类,它创建的对象进行的操作都是原子性的,因此能够保证值的同步性。
对 AtomicInteger 的具体解释这里就不进行了,有兴趣可以自行研究。
String 类型的话建议直接使用 StringBuilder。
实例化对象的话就更没有问题了。
但要记住一点,不要在后续过程中给实例化对象重新赋值新地址就行了。