Java8中Lambda那搞笑的闭包

Java8 有一大特色就是引入的 Lanbda 表达式,一击掀起千层浪。

一、闭包

    闭包这个概念,其实这是每个前端工程师,或者再广义一点,每个深入学习 JavaScript 的人必走的一条路。

    在此引用松本行弘(Ruby之父)在《代码的未来》一书中的一段话:闭包就是把函数以及变量包起来,使得变量的生存周期延长。闭包跟面向对象是一棵树上的两条枝,实现的功能是等价的。

    换个理解方式,就是将作用域在函数内的变量引用使用某种方式包起来,这样它的生命周期便加长了。
</p>

二、Java 中的闭包

    其实在 Java 6 里面,我们可以写如下代码:

1
2
3
4
5
6
7
8
9
10
11
12
public&nbsp;static&nbsp;Supplier<Integer>&nbsp;testClosure(){
&nbsp;final&nbsp;int&nbsp;i&nbsp;=&nbsp;1;
&nbsp;return&nbsp;new&nbsp;Supplier<Integer>()&nbsp;{
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;@Override
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;public&nbsp;Integer&nbsp;get()&nbsp;{
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;return&nbsp;i;
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;}
&nbsp;};
}
public&nbsp;interface&nbsp;Supplier<T>&nbsp;{
&nbsp;T&nbsp;get();
}

    解释下:

        其实并没有多少奇淫技巧去,作用就是在内部的匿名对象里面,任然可以返回属于 testClosure 函数的局部变量 i,所以这就达到了延长 i 的生命的周期的作用,其实这个就是很简单的闭包小实践。


三、回到 Lambda

    在 Java 8 的 Lambda 表达式中,回到此文的重点中。如下简单的代码便是 Lambda 的最基础实践:

1
2
3
4
5
6
public&nbsp;static&nbsp;Supplier<Integer>&nbsp;testClosure()&nbsp;{
&nbsp;int&nbsp;i&nbsp;=&nbsp;1;
&nbsp;return&nbsp;()&nbsp;->&nbsp;{
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;return&nbsp;i;
&nbsp;};
}

    匿名函数里的变量引用,也叫做变量引用泄露,其实会导致线程安全问题(JavaScript 这类单线程语言不必担心过多),但为什么 Java 8 却可以大张旗鼓地让我们这样使用呢?为什么 i 不需要申明成 fina 类型的呢?

    其实这就是一小块语法糖罢了,因为在 Lambda 表达式引用外部局部变量时,已经默认将其视为了 final 类型了,所以并不需要我们手动去申明 final。

    但是当我们改变变量的值得时候,编译这关就已经过不去了,即编译会报错,如下代码,编译是无法通过的:

1
2
3
4
5
6
7
public&nbsp;static&nbsp;Supplier<Integer>&nbsp;testClosure()&nbsp;{
&nbsp;int&nbsp;i&nbsp;=&nbsp;1;
&nbsp;i++;
&nbsp;return&nbsp;()&nbsp;->&nbsp;{
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;return&nbsp;i;&nbsp;//这里会出现编译错误
&nbsp;};
}


四、总结

    都说 Ruby 语法糖很多,但是当 Java 也加入了上文提到的语法糖的时候,突然感觉好酸,这块糖并不甜,还不如手动添加一个 final。

    总之,开发的时候利弊都有,只能说,这种默认设置,加入了一点点,很小的一点点搞笑的元素。












------ 本文结束 感谢阅读 ------
0%