lambda表达式和闭包
lambda表达式和闭包
熟悉的Javascript或者Ruby的同学,可能对另一个名词:闭包更加熟悉。因为一般闭包的示例代码,长得跟lambda差不多,导致我也在以前很长一段时间对这两个概念傻傻分不清楚。其实呢,这两个概念是完全不同维度的东西。
闭包是个什么东西呢?我觉得Ruby之父松本行弘在《代码的未来》一书中解释的最好:闭包就是把函数以及变量包起来,使得变量的生存周期延长。闭包跟面向对象是一棵树上的两条枝,实现的功能是等价的。
这样说可能不够直观,我们还是用代码说话吧。其实Java在很早的版本就支持闭包了,只是因为应用场景太少,这个概念一直没得到推广。在Java6里,我们可以这样写:
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();
}
看出问题了么?这里i是函数testClosure的内部变量,但是最终返回里的匿名对象里,仍然返回了i。我们知道,函数的局部变量,其作用域仅限于函数内部,在函数结束时,就应该是不可见状态,而闭包则将i的生存周期延长了,并且使得变量可以被外部函数所引用。这就是闭包了。这里,其实我们的lambda表达式还没有出现呢!
而支持lambda表达式的语言,一般也会附带着支持闭包了,因为lambda总归在函数内部,与函数局部变量属于同一语句块,如果不让它引用局部变量,不会让人很别扭么?例如Python的lambda定义我觉得是最符合λ算子的形式的,我们可以这样定义lambda:
#!/usr/bin/python
y = 1
f=lambda x: x + y
print f(2)
y = 3
print f(2)
输出:
3
5
这里y其实是外部变量。
Java中闭包带来的问题
在Java的经典著作《Effective Java》、《Java Concurrency in Practice》里,大神们都提到:匿名函数里的变量引用,也叫做变量引用泄露,会导致线程安全问题,因此在Java8之前,如果在匿名类内部引用函数局部变量,必须将其声明为final,即不可变对象。(Python和Javascript从一开始就是为单线程而生的语言,一般也不会考虑这样的问题,所以它的外部变量是可以任意修改的)。
在Java8里,有了一些改动,现在我们可以这样写lambda或者匿名类了:
public static Supplier<Integer> testClosure() {
int i = 1;
return () -> {
return i;
};
}
这里我们不用写final了!但是,Java大神们说的引用泄露怎么办呢?其实呢,本质没有变,只是Java8这里加了一个语法糖:在lambda表达式以及匿名类内部,如果引用某局部变量,则直接将其视为final。我们直接看一段代码吧:
public static Supplier<Integer> testClosure() {
int i = 1;
i++;
return () -> {
return i; //这里会出现编译错误
};
}
明白了么?其实这里我们仅仅是省去了变量的final定义,这里i会强制被理解成final类型。很搞笑的是编译错误出现在lambda表达式内部引用i的地方,而不是改变变量值的i++
…这也是Java的lambda的一个被人诟病的地方。我只能说,强制闭包里变量必须为final,出于严谨性我还可以接受,但是这个语法糖有点酸酸的感觉,还不如强制写final呢…
lambda表达式和闭包的更多相关文章
- 浅析匿名函数、lambda表达式、闭包(closure)区别与作用
浅析匿名函数.lambda表达式.闭包(closure)区别与作用 所有的主流编程语言都对函数式编程有支持,比如c++11.python和java中有lambda表达式.lua和JavaScript中 ...
- C# 从CIL代码了解委托,匿名方法,Lambda 表达式和闭包本质
前言 C# 3.0 引入了 Lambda 表达式,程序员们很快就开始习惯并爱上这种简洁并极具表达力的函数式编程特性. 本着知其然,还要知其所以然的学习态度,笔者不禁想到了几个问题. (1)匿名函数(匿 ...
- 理解Lambda表达式和闭包
了解由函数指针到Lambda表达式的演化过程 Lambda表达式的这种简洁的语法并不是什么古老的秘法,因为它并不难以理解(难以理解的代码只有一个目的,那就是吓唬程序员) #include " ...
- python3 入门 (三) 函数与lambda表达式、闭包
函数 是组织好的.可重复使用的.用来实现单一或相关联功能的代码段. 函数代码块以def关键词开头,后接函数标识符名称和圆括号() 任何传入参数和自变量必须放在圆括号中间.圆括号之间可以用于定义参数 函 ...
- 背后的故事之 - 快乐的Lambda表达式(一)
快乐的Lambda表达式(二) 自从Lambda随.NET Framework3.5出现在.NET开发者眼前以来,它已经给我们带来了太多的欣喜.它优雅,对开发者更友好,能提高开发效率,天啊!它还有可能 ...
- Spark中Lambda表达式的变量作用域
通常,我们希望能够在lambda表达式的闭合方法或类中访问其他的变量,例如: package java8test; public class T1 { public static void main( ...
- 深入浅出 Java 8 Lambda 表达式
摘要:此篇文章主要介绍 Java8 Lambda 表达式产生的背景和用法,以及 Lambda 表达式与匿名类的不同等.本文系 OneAPM 工程师编译整理. Java 是一流的面向对象语言,除了部分简 ...
- Lambda 表达式,Java中应用Lambda 表达式
一.Lambda 表达式 简单来说,编程中提到的 lambda 表达式,通常是在需要一个函数,但是又不想费神去命名一个函数的场合下使用,也就是指匿名函数. 链接:知乎 先举一个普通的 Python 例 ...
- 【转】背后的故事之 - 快乐的Lambda表达式(一)
快乐的Lambda表达式(二) 自从Lambda随.NET Framework3.5出现在.NET开发者眼前以来,它已经给我们带来了太多的欣喜.它优雅,对开发者更友好,能提高开发效率,天啊!它还有可能 ...
随机推荐
- css3 drop-shaow阴影效果
<!DOCTYPE html> <html lang="en"> <head> <meta charset="utf-8&quo ...
- Android 获取有规律资源Id解决方案
在多个有规律的资源ID获取的时候,可以使用getIdentifier方法来获取,来获取. 用到场景:工具类打成.jar包的时候,有时候会需要引用到res中的资源,这时候不能将资源一起打包,只能通过反射 ...
- jquery学习(3)--高级选择器
自己手写的学习笔记.常规选择器: /****************学习--高级选择器(1)****************/---高级选择器:ie7+ 层次选择器: 后代选择器 ul li ...
- codeforces 3D . Least Cost Bracket Sequence 贪心
题目链接 给一个字符串, 由( ) 以及? 组成, 将?换成( 或者 ) 组成合法的括号序列, 每一个?换成( 或者 ) 的代价都不相同, 问你最小代价是多少, 如果不能满足输出-1. 弄一个变量nu ...
- 标准C编程-笔记全集
C语言的基本概念 编写一个简单的C程序,后缀名保存为c(本次文件名为a.c) gcc:对c程序进行编译和连接:gcc a.c ./a.out:运行程序,输出程序的结果:其中a是c程序的文件名 说明:其 ...
- ThinkPHP中ajax提交数据
最近在做项目时遇到了一些需要从页面用ajax提交数据到后台的操作,无奈本人技术有限,网上苦寻,研究了一下ajax和thinkPHP的结合,黄天不负苦心人,终于搞定了. 闲话少叙,进入正题:我需要从页面 ...
- 面向对象程序设计-C++_课时17函数重载和默认参数
函数重载,区别一是参数类型不同,二是参数个数不同. 默认参数可以多于1个,但必须放在参数序列的后部. 尽量不要用默认参数,会影响阅读 error C2668: “f”: 对重载函数的调用不明确 #in ...
- css学习笔记二
下面来总结一下盒子模型,流式布局,浮动布局,层布局(定位布局). 1.盒子模型 有二种:IE盒子模型 和 标准w3c盒子模型 1)IE的盒子模型的content包含了padding和border 2) ...
- 君子性非异也,善假于物也 - Threejs 引入TrackballControls 查看场景
君子性非异也,善假于物也 - Threejs 引入TrackballControls 查看场景 太阳火神的漂亮人生 (http://blog.csdn.net/opengl_es) 本文遵循" ...
- IOS系列——NStimer
Timer经常使用的一些东西 1. 初始化 timer = [NSTimer scheduledTimerWithTimeInterval:1 target:self selector:@select ...