前言
lambda表达式不能说常用吧,但偶尔还是需要用到的。关于lambda表达式,是我学python的时候接触到的概念,仔细想想也有两年了。前段时间的面试有提到java中的lambda表达式,当时自己的回答还是比较笼统的,比如作为类似语法糖的存在,通常在比较器里面写,可以免写匿名类等等。我个人感觉回答的不是很好,那这篇文章就来讲讲我们一直在用的lambda表达式吧。
正文
概念
lambda表达式在很多语言中都有,那我个人比较熟悉的python与java中的lambda。那lambda表达式究竟是啥呢?根据百度百科的定义:
lambda表达式是一个匿名函数,基于数学中的λ演算得名,可以表示闭包。
这么说谁听得懂哦?没错,没有实践的概念都是天书。
那我们先来讲讲啥是匿名函数。
匿名函数
所谓匿名函数,正如字面所讲,就是没有名字的函数,正常我们在定义函数时,会定义它的名称,其他地方调用时直接用它的名称进行调用即可。
那如果我们只需要使用一次这个函数,并且不想给他取名,那这时我们就要用到匿名函数了。
所谓的lambda表达式就是匿名函数的一种表示方式。
python中的lambda表达式
正常我们在定义函数时会这么定义:
1 | def f(x): |
以上我们定义了一个有名称的函数,而如果使用lambda表达式的话
1 | g = lambda x : x + x |
那这两种定义函数的方式的功能都是一样的,那通常情况下我们不会把lambda表达式赋值给任何变量,这相当于可以使用这个变量调用匿名函数,就已经不符合匿名函数的定义。
那在python中使用到lambda表达式的场景有哪些呢?
- 最常见的当然就是一些python中的内置函数,比如作为比较器的时候,如sorted函数,
sorted([1,2,3],key=lambda x : -x)
,又比如map函数,map(lambda x: x+1, [1,2,3])
。 - 那还有就是函数的返回可以是一个匿名函数,例如
return lambda x,y : x*y
,这个我比较少用。 - 还有就是可以通过lambda表达式将某个函数屏蔽,例如前端可以通过
console.log = ()=>{}
来屏蔽log输出,原因是把log函数给替换成了没有功能的函数,那python中也可以,比如time.sleep = lambda x : None
,就可以屏蔽sleep函数。
Java中的lambda表达式
Java 8中支持了lambda表达式,那么带来的结果就是代码更加简洁。它的亮点就是可以替代匿名内部类。
java中的lambda表达式的语法如下:
1 | (parameters) -> expression |
在java 8之前假设要新建一个线程,在之前的文章我有写过,通常我们需要这么写:
1 | new Thread(new Runnable() { |
那在java 8之后我们可以通过lambda表达式省去这个匿名runnable对象。
1 | new Thread( |
当然,我们最常见的还是传入比较器的时候,例如在java 8之前,我们需要匿名内部类来重写比较器的compare方法。例如使用优先级队列需要建立堆时,
1 | Queue<Integer> queue = new PriorityQueue<>(new Comparator<Integer>() { |
那这边ieda就会提示我是否转换为lambda表达式,我们转换一下
1 | Queue<Integer> queue = new PriorityQueue<>((o1, o2) -> o2 - o1); |
我们代码更加直观了。当然这得益于jvm自动帮助我们判断参数类型。
那为什么可以简写呢?其实我们可以直接跟进源码看看,首先是new Thread,我们可以发现Thread有个构造函数可以传入Runnable对象,而Runnable是一个接口;接着我们看PriorityQueue,也可以发现有个构造函数可以传入Comparator对象,而Comparator也是个接口。
所以不难猜测,其实能使用lambda表达式是因为有相应的构造函数与接口的存在。那书写后编译时,自动帮我们匹配进相应的构造函数,自动判断类型,等等。这就是lambda表达式所帮我们做的。
Java lambda表达式深入
那通过以上我们可以知道,lambda表达式其实作为的是一种类似语法糖的存在,可以更直观的书写代码。lambda表达式似乎与匿名内部类可以相互替换。但事实并非如此。
当我们书写一个匿名内部类时,在编译阶段我们可以发现发现多出了一个class文件,但我们使用lambda表达式后,只有一个class文件。
继续查看使用lambda表达式后编译的class文件,我们可以发现lambda表达式其实是被封装成主类的一个私有静态方法。
还有一点是this的使用,在匿名内部类中,this指向的是自己,而lambda表达式中,this指向的是外部类。
Java lambda表达式的性能问题
这个问题其实困扰了我很久,在网上找了许多文章,有说性能有损失,有说没差多少。那在我测试后发现,lambda表达式确确实实有一点性能上的损失,但是并不大。那在我做LeetCode的其中一道题目中使用到的优先级队列,那使用匿名内部类与使用lambda表达式的时间分别是40-60ms与600-700ms(大概),所以也就是说在某些用例上面,lambda确实是慢于匿名内部类的。
那关于这个问题,如果之后还有遇到会单独写写文章还有测试方法。
总结
这篇文章讲了什么是lambda表达式以及在python和java中的常用方法。那在python中,由于这门语言本身就追求简洁与方便,所以在大部分函数中传入lambda表达式本身就是十分省事的存在,并且不会把函数定义写入整个文件中,从而污染环境。
在java中,其实我个人倾向于把lambda表达式看做是一种语法糖,减少书写量,因为它能做到大部分匿名内部类的所能做的事,从代码简洁性来看肯定是更好的。
那函数式编程越加火热的今天,lambda表达式作为函数式编程的一份子,肯定是会有越来越多语言支持,甚至当成主要书写方式。