一、闭包
闭包这个概念,其实这是每个前端工程师,或者再广义一点,每个深入学习 JavaScript 的人必走的一条路。在此引用松本行弘(Ruby之父)在《代码的未来》一书中的一段话:闭包就是把函数以及变量包起来,使得变量的生存周期延长。闭包跟面向对象是一棵树上的两条枝,实现的功能是等价的。 换个理解方式,就是将作用域在函数内的变量引用使用某种方式包起来,这样它的生命周期便加长了。
二、Java 中的闭包
其实在 Java 6 里面,我们可以写如下代码:public static Supplier<Integer> testClosure(){ final int i = 1; return new Supplier<Integer>() { @Override public Integer get() { return i; } }; } public interface Supplier<T> { T get(); }解释下:
其实并没有多少奇淫技巧去,作用就是在内部的匿名对象里面,任然可以返回属于 testClosure 函数的局部变量 i,所以这就达到了延长 i 的生命的周期的作用,其实这个就是很简单的闭包小实践。
三、回到 Lambda
在 Java 8 的 Lambda 表达式中,回到此文的重点中。如下简单的代码便是 Lambda 的最基础实践:public static Supplier<Integer> testClosure() { int i = 1; return () -> { return i; }; }匿名函数里的变量引用,也叫做变量引用泄露,其实会导致线程安全问题(JavaScript 这类单线程语言不必担心过多),但为什么 Java 8 却可以大张旗鼓地让我们这样使用呢?为什么 i 不需要申明成 fina 类型的呢? 其实这就是一小块语法糖罢了,因为在 Lambda 表达式引用外部局部变量时,已经默认将其视为了 final 类型了,所以并不需要我们手动去申明 final。
但是当我们改变变量的值得时候,编译这关就已经过不去了,即编译会报错,如下代码,编译是无法通过的:
public static Supplier<Integer> testClosure() { int i = 1; i++; return () -> { return i; //这里会出现编译错误 }; }
四、总结
都说 Ruby 语法糖很多,但是当 Java 也加入了上文提到的语法糖的时候,突然感觉好酸,这块糖并不甜,还不如手动添加一个 final。总之,开发的时候利弊都有,只能说,这种默认设置,加入了一点点,很小的一点点搞笑的元素。
文章评论