lambda表达式/闭包 整理
java中lambda表达式【闭包、匿名函数】——一个方法【函数没有名称,匿名函数】,可以赋值给一个变量,那它是什么类型呢?——一个接口【函数式接口,只能有一个函数的接口】
闭包广泛用于回调函数、函数式编程中。
当有字段为函数式接口类型时,此字段可以看做是一个方法,此字段实例化时此方法一定是有方法体的【方法体代码就是数据】。
JAVA8中新特性
![](https://img2023.cnblogs.com/blog/1075697/202302/1075697-20230223114311413-23111584.png)
闭包,关闭的是什么?
Lambda表达式和匿名内部类很像。在IDEA中,写了一个匿名内部类,IDEA会给你提示为替换Lambda表达式,想一想,为什么呢?
java有几种内部类【可以访问外部类变量,外部类不能访问内部类,包含关系】
- 成员内部类【类大括号里边定义的类】
- 静态成员内部类【类大括号里边定义的有static的类】
- 匿名内部类【直接new并返回的没有名字的内部类,特殊的局部内部类】
- 局部内部类【方法中】
匿名类和匿名函数的区别 ——一个是类,一个是函数
示例代码:
public class Test2 { private String text = " world"; public interface IHello { void sayHello(); } private void hello() { //类 IHello helloAnonymousClass = new IHello() { @Override public void sayHello() { System.out.print(this + " Hello helloAnonymousClass " + text + "\n"); } }; //函数 IHello helloAnonymousFunction = () -> { System.out.print(this + " Hello helloAnonymousFunction " + text + "\n"); }; helloAnonymousClass.sayHello(); helloAnonymousFunction.sayHello(); } public static void main(String[] args) { Test2 test2 = new Test2(); test2.hello(); test2.hello(); } }
//运行结果
com.road.talk.entity.Test2$1@19bb089b Hello helloAnonymousClass world
com.road.talk.entity.Test2@4563e9ab Hello helloAnonymousFunction world
com.road.talk.entity.Test2$1@11531931 Hello helloAnonymousClass world
com.road.talk.entity.Test2@4563e9ab Hello helloAnonymousFunction world
局部变量在Lambda中重新赋值,报错
示例:
有一个关键:局部变量是final修饰的引用变量则可以修改,只要不是指向新地址即可。就好像final修饰的变量可以再次修改值,但指向该对象或数组的地址的引用不能修改
本质原因:Lambda 是一个方法,在线程中使用,在执行环境中,可能该局部变量已经被回收了,访问的是一个副本,修改副本没什么意义,且这个副本已经有值【局部变量必须初始化】,因此有了这个限制。相当于final修饰的。封闭起来就是闭包的名字由来。
![](https://img2023.cnblogs.com/blog/1075697/202302/1075697-20230223114625626-1537573620.png)
Lambda的——方法引用
在Java 8中有一个函数式接口的包,里面定义了大量可能用到的函数式接口(java.util.function (Java Platform SE 8 ))
其他语言关于闭包的东西:
C#建议38:小心闭包中的陷阱【闭包在局部变量声明的地方产生】
闭包——实质在IL中生成了对应的闭包对象【即匿名类,包括局部变量参数,闭包函数】,闭包的对象产生在参数声明的地方。例如:for循环中的变量
![](https://img2023.cnblogs.com/blog/1075697/202302/1075697-20230223114706597-1645456491.png)
![](https://img2023.cnblogs.com/blog/1075697/202302/1075697-20230223114714783-2073884834.png)
C#闭包——使用声明的委托类型变量接收 lambda表达式。
js闭包:
由于在Javascript语言中,只有函数内部的子函数才能读取局部变量,因此可以把闭包简单理解成"定义在一个函数内部的函数"。
所以,在本质上,闭包就是将函数内部和函数外部连接起来的一座桥梁。
五、使用闭包的注意点
1)由于闭包会使得函数中的变量都被保存在内存中,内存消耗很大,所以不能滥用闭包,否则会造成网页的性能问题,在IE中可能导致内存泄露。解决方法是,在退出函数之前,将不使用的局部变量全部删除。
2)闭包会在父函数外部,改变父函数内部变量的值。所以,如果你把父函数当作对象(object)使用,把闭包当作它的公用方法(Public Method),把内部变量当作它的私有属性(private value),这时一定要小心,不要随便改变父函数内部变量的值。
https://blog.csdn.net/xiangang12202/article/details/122916258
源码,是痛苦的,又是快乐的,如果没有这痛苦,也就没有了这快乐!