什么是lambda表达式,引用变量为什么为final

lambda表达式,引用变量为什么为final

什么是lamda表达式

lambda表达式是java8提供的一种新特性,能进行简单的函数式编程,lambda表达式是一个匿名函数,可以把lambda表达式理解为一段可以传递的代码(将代码像数据一样进行传递),使得可以写出更简洁、更灵活的代码。

lamda表达式书写如下:

Runnable runnable1=()-> System.out.println("lambda表达式跑起来了");
list.stream().filter((e)->e.getAge()>18).forEach(System.out::println);

函数式接口的注解

@FunctionalInterface

lambda表达式的本质

lambda表达式本质是解决匿名内部类的问题,如下面的等价转化

匿名内部类

Runnable runnable=new Runnable() {
            @Override
            public void run() {
                System.out.println("匿名内部类跑起来了");
            }
        };

lambda表达式

Runnable runnable1=()-> System.out.println("lambda表达式跑起来了");

上面2个是等价的,lambda表达式就是为了替代匿名内部类

为什么引用的变量是final

上面说到,lambda表达式是替代匿名内部类,并且可以理解为一段可以传递的代码。那我们在引用局部变量时,为啥是要修饰final。

  1. lambda表达式的内容可用传递到其他线程去执行,这样会导致局部变量的问题,如果局部变量的方法执行完,局部变量就消失了,你再另外的线程修改局部变量的值,当然就出现错误了。
  2. 在堆栈的角度,lambda表达式他是匿名内部类,类存在于堆中,而方法的局部变量是存在于虚拟机栈中,方法执行完,栈帧就出栈了,局部变量也就不存在了,而堆中的lambda表达式仍可存在,如果此时修改局部变量,就会出错

所以,lambda表达式引用的变量要为不可变,即用final修饰,传入的变量会生成一个不可变的副本,也避免并发问题,在java8后可以不用final修饰,但是实质上也是个final的变量,修改就会报错。

Stream

lambda表达式的好伙伴Stream,是java8的新特性,用于算法和计算,更像一个高级的迭代Iterator,对于元素集合统一、快速、并行操作的一种方式,充分利用多核优势,配合lambda表达式、链式结构对集合进行许多有用的操作,示例如下:

List adultList= persons.stream()
                       .filter(p -> p.getAge() > 18)
                       .map(person -> new Adult(person))
                       .collect(Collectors.toList());

int countOfAdult=persons.stream()
                       .filter(p -> p.getAge() > 18)
                       .map(person -> new Adult(person))
                       .count();

总结

lambda表达式让我们方便点的进行函数式编程,减少了代码量,也美化了代码,让我们继续使用lambda表达式吧。

### lambda表达式中赋值变量的数据类型 在C++中,`lambda`表达式是一种匿名函数对象,其底层实现依赖于编译器生成的唯一类名[^1]。当定义一个`lambda`表达式时,它实际上会创建一个新的匿名类实例,并且该类实现了调用操作符(`operator()`)。这意味着每个`lambda`表达式的类型实际上是独一无二的。 对于`lambda`表达式中的局部变量捕获和参数传递,存在一些特定规则: #### 局部变量捕获 - 如果`lambda`表达式需要访问外部作用域中的变量,则这些变量必须满足“实质上是`final`”的要求,即它们在整个生命周期内不会发生更改[^5]。 - 这些被捕获的变量会被复制到`lambda`表达式的闭包环境中,或者通过引用的方式绑定到原始变量上(取决于捕获模式 `[=]` 或 `[&]`)。 #### 参数列表与隐式推导 - `lambda`表达式的参数类型可以显式指定或让编译器自动推断。例如,在不提供具体类型的场景下,编译器能够依据上下文来决定实际使用的数据类型[^2]。 以下是几个例子展示如何处理不同类型以及捕获机制: ```cpp #include <iostream> using namespace std; int main() { int x = 42; // 显式声明参数类型 auto explicitLambda = [](const int param) -> void { cout << param * 2 << endl; }; explicitLambda(x); // 隐式推导参数类型 auto implicitLambda = [&](auto value) { cout << value + x << endl; }; implicitLambda(7); return 0; } ``` 上述代码片段展示了两种不同风格的`lambda`定义方式及其应用情况。第一个`explicitLambda`强制指定了输入参数为整数;第二个则允许任意兼容加法运算的对象传入,并利用了对外围变量`x`的引用捕捉功能。 需要注意的是,尽管两者的逻辑看起来相似,但由于各自所属类别差异巨大——一个是独立实体,另一个关联至原生范围内的某个固定数值——所以即便两者行为一致也无法互相转换或比较。 最后强调一点关于Java平台上的区别对待:虽然同样支持`lambda`语法糖衣包裹下的简化版匿名内部类构建过程[^3][^4] ,但因应宿主语言特性的缘故,在那里讨论的主题更多集中在其接口适配能力而非细粒度控制层面的东西。 ### 结论 综上所述,`lambda`表达式所涉及的各种元素均遵循严格的规定以保障程序健壮性的同时也赋予开发者极大的灵活性去完成复杂任务需求。
评论 2
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值