为什么lambda表达式要用final

为什么 Lambda 表达式(匿名类) 不能访问非 final  的局部变量呢?

因为实例变量存在堆中,而局部变量是在栈上分配,Lambda 表达(匿名类) 会在另一个线程中执行。如果在线程中要直接访问一个局部变量,可能线程执行时该局部变量已经被销毁了,而 final 类型的局部变量在 Lambda 表达式(匿名类) 中其实是局部变量的一个拷贝。

 

Java 8 的 Lambda 可以捕获什么变量呢?

(1). 捕获实例或静态变量是没有限制的 (可认为是通过 final 类型的局部变量 this 来引用前两者);

(2). 捕获的局部变量必须显式的声明为 final 或实际效果的的 final 类型。

回顾一下我们在 Java 8 之前,匿名类中如果要访问局部变量的话,那个局部变量必须显式的声明为  final。

Java 7 要求这个局部变量必须是 final  类型的,否则在匿名类中不可引用。

上面同样的代码放到 Java 8 中可以编译通过,难道 Java 8 不需要 version 是 final 的类型吗?不尽然

1

2

3

4

5

6

7

8

String version = "1.8";

foo(new Supplier() {

  @Override

  public String get() {

   return version;

  }

});

version = "1.7"//在 Java 8 下注释这行就能编译通过,否则报出前面同样的错误

也就是在 Java 8 下,即使局部变量未声明为 final 类型,一旦在匿名类中访问了一下就被强型加上了 final 属性,所以后面就无法再次给 version 赋值了。

前面演示了是匿名类,在 Java 8 中换成 Lambda 表达式也是一回事

1

2

3

String version = "1.8";

foo(() -> version); //对局部变量 version 的访问让 version 变成 final 了

version = "1.7";  //有了这行就编译不过了

因此,Java 8 的 Lambda 表达式访问局部变量时虽然没有硬性规定要被声明为 final,但实质上是和 Java 7 一样的。

总之一个局部变量如果要在 Java 7/8  的匿名类或是 Java 8 的 Lambda 表达式中访问,那么这个局部变量必须是 final 的。

注意,并不是 Lambda 开始访问时那个局部变量才变为 final,这是编译器的需求,例如

1

2

3

String version = "1.8";

version = "1.7";      //注释掉这行或下行中另一行才能编译通过

foo(() -> version );  //这行让编译器决定给 version 加上 final 属性

换句话说,如果在匿名类或 Lambda 表达式中访问的局部变量,如果不是 final 类型的话,编译器自动加上 final 修饰符。

 

 

 

  • 7
    点赞
  • 12
    收藏
    觉得还不错? 一键收藏
  • 2
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 2
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值