如何在lambda表达式中调用外部变量

如何在lambda表达式中调用外部变量


先来看一下 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

实例化对象的话就更没有问题了。
但要记住一点,不要在后续过程中给实例化对象重新赋值新地址就行了。

猜你喜欢

转载自blog.csdn.net/weixin_48140105/article/details/126991130