有奖问答】- 为什么 Lambda 表达式要用 final 关键字修饰变量?

简介: 有奖问答】- 为什么 Lambda 表达式要用 final 关键字修饰变量?

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

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


Ps:这里指的“拷贝”是拷贝局部变量的值,但是引用地址还是不变的,那么为何还需要拷贝呢?不是多此一举吗?如有高手路过,指点一二哈~

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

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


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


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


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


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


//

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 表达式也是一回事

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,这是编译器的需求,例如


/

String version = "1.8";
version = "1.7";      // 注释掉这行或下行中另一行才能编译通过
foo(() -> version );  // 这行让编译器决定给 version 加上 final 属性

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

目录
相关文章
|
1月前
|
存储 安全 编译器
【C++ 关键字 类型限定符 】揭秘C++编程中的神秘元素:深入了解volatile关键字的强大作用
【C++ 关键字 类型限定符 】揭秘C++编程中的神秘元素:深入了解volatile关键字的强大作用
21 0
|
29天前
|
存储 C语言
变量和常量的例子
变量和常量的例子
7 1
|
30天前
|
安全 算法 编译器
【C++ 基础 ()和{}括号】深入探索 C++ 的变量初始化:括号和大括号的奥秘
【C++ 基础 ()和{}括号】深入探索 C++ 的变量初始化:括号和大括号的奥秘
39 0
|
1月前
|
算法 C语言 C++
【C/C++ 关键字 类型限定符 】 C/C++ 中 const的用法:限制变量的作用域和可见性
【C/C++ 关键字 类型限定符 】 C/C++ 中 const的用法:限制变量的作用域和可见性
20 0
|
1月前
|
JavaScript 前端开发 Java
23、匿名类的排序、Lambda 表达式、方法引用
23、匿名类的排序、Lambda 表达式、方法引用
17 0
|
2月前
|
Java 编译器 开发者
JDK 10中的局部变量类型推断:探索var关键字的新境界
在JDK 10中,Java语言引入了一个令人兴奋的新特性:局部变量类型推断。通过使用关键字"var",开发者可以在声明局部变量时省略类型注解。这一改进旨在简化代码,提高可读性,并使Java更接近于动态类型脚本语言。本文将深入探讨局部变量类型推断的工作原理、优点、限制以及在实际项目中的应用。
|
8月前
|
Java 编译器 Kotlin
Kotlin 中变量,类型,表达式,函数详解
Kotlin 中变量,类型,表达式,函数详解
68 0
|
7月前
|
Java
final 类,常量,方法的解释
final 类,常量,方法的解释
55 1
|
存储 C#
C# 修饰关键字解析
C# 修饰关键字解析