java程序在1.8支持了闭包,但是在oracle官网又找不到官方资料,在翻了很多网站后写了下面这些东西
闭包(closure)
来自百度百科的定义
闭包就是能够读取其他函数内部变量的函数。例如在javascript中,只有函数内部的子函数才能读取局部变量,所以闭包可以理解成“定义在一个函数内部的函数“。在本质上,闭包是将函数内部和函数外部连接起来的桥梁。
来自wikipedia的定义
闭包,(英语:closure),这里指点集拓朴的术语:在拓扑空间里,子集S 的闭包是指由S 的所有点及S 的极限点所组成的一个集合;直观上来说,即为所有“靠近”S 的点所组成的集合。在子集S 的闭包内的点称为S 的闭包点。闭包的概念在许多方面能与内部的概念相对比。
如何理解闭包
闭包总体分为两个部分
- 函数本身
- 函数周围的环境
JavaScript闭包
等级1
指针关系
1 |
|
在这段代码中,我们看到了一个变量a,然后由一个函数lambdaFun指向并维护了这个变量a,这段代码最终将会输出11;
JavaScript指向了一个范围;
等级2
作用域
我们可以继续扩展这段代码来理解:
1 | function func() { |
我们用v来接收func的结果,而在v = func();之后,func函数的作用域已经超出,但是闭包函数仍然存在,当我们调用v.get(‘inc’)()之后,对象a依然会发生变化。
java闭包
等级1
指针关系
1 | public class Test{ |
为什么有一行注释代码呢?实际上,如果将注释打开,代码将会无法通过编译,这是java闭包局限的局限之一,
只能在封闭范围内将变量转化为final的。
等级2
作用域
让我们针对JavaScript等级2的代码含义,转换为java代码实现1
2
3
4
5
6
7
8
9
10
11
12public class Test{
public static void main(String[] args) {
Map map=func();
}
public static Map<String, Supplier> func() {
int a = 10;
Map<String, Supplier> map = new HashMap<>();
map.put("val", () -> a);
//map.put("inc", () -> a++);
return map;
}
}
仍然带着一行注释,这一行代码依然不会通过编译,java会在执行() -> a之后得到a的副本,
所以在运行() -> a++代码的时候实际上操作的是a的副本,如果变量a分配是在栈上发生的,那这太混乱了。让我们将变量分配在堆上1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20public class Test{
static int a = 10;
public static Map<String, Supplier> func() {
Map<String, Supplier> map = new HashMap<>();
map.put("val", () -> a);
map.put("inc", () -> a++);
return map;
}
public static void main(String[] args) {
Map<String, Supplier> map=func();
Supplier s1=map.get("val");
Supplier s2=map.get("inc");
Supplier s3=map.get("val");
System.out.println(s1.get());//10
System.out.println(s2.get());//10
System.out.println(s3.get());//11
}
}
我们在此时做到了闭包,使用Supplier的get方法操作了func()方法里的a变量(虽然这个变量是一个静态的类变量)
为什么java要这么做
对于JavaScript来说,闭包的意义在于覆盖/封闭变量,在其看来,函数func创建了一个对象,而我们直接操作了对象的属性1
2v = func();
console.log(v.get('val')());
而Java语言里,每个java类都是为了描述对象而存在的,我们为对象赋予了方法,外界通过选定对象和方法来修改属性;
相比而言,Java确实实现的不如JavaScript灵活,但是也避免了JavaScript里常常发生的灵异变化。