lambda表达式杂谈

时间:2023-01-15 22:19:14
var personInfo = [ { name: "张三", age: 20, gender: "male" },
{ name: "李四", age: 18, gender: "male" },
{ name: "王五", age: 19, gender: "male" },
{ name: "春香", age: 17, gender: "female" },
{ name: "夏香", age: 21, gender: "female" },
{ name: "秋香", age: 22, gender: "female" },
{ name: "冬香", age: 18, gender: "femalt" }];

上面的数据存放着一组人员姓名、年龄、性别相关的信息。 现在有一个需求, 获得年龄20岁以上,性别为女的人的姓名。 看到需求后, 很多人脑袋中产生的解决方案可能是这样的

    var result = [];
for(var i = 0; i < personInfo.length; i++) {
var item = personInfo[i];
if( item.age >= 20 && item.gender == "female") {
result2.push(item.name);
}
}
console.log(result);

代码执行的结果是[“夏香”,“秋香”]

很好,结果正确,考试的话肯定给满分。

但是这种实现方法有点过时,不潇洒,现在流行的做法应该是这样子

    let result = personInfo.filter(item=>item.age >= 20 && item.gender == 'female')
.map(item=> item.name);
console.log(result);

看, 一样的实现了要求,代码却简洁了许多。如果把代码的实现方式和我们平时的穿着来做对比, 这种实现方式就像是走时尚潮流尖端的穿着打扮,比如说电视里走在t台上的模特的穿着,因为这是es6的语法,由于要兼容老式浏览器的缘故,很多程序员不敢明目张胆的使用。

而前一种方法就像是上世纪的中山装,你穿出去没问题,但肯定会被人家说是土鳖。

更一般的符合大众审美的写法是这样子的

   var result = personInfo.filter(function(item){
return item.age >= 20 && item.gender == 'female';
}).map(function(item){
return item.name;
});
console.log(result);

这种写法和第一种写法思路是相同的, 不同点在于,第一种方法使用的是lamda表达式,而这种方法使用的是匿名函数。

事实上,匿名函数在功能上和lambda表达式是没有差别的,只是叫法不一样,此外,lambda表达式写法更加简洁一些。

在javascript中,lamda表达式可以这样写

()=>{}

而匿名函数要这样写

function(){return;}

lambda表达式相对于匿名函数可以省略function和return两个关键字。

lambda的原理就是把函数当做另一个函数的参数来使用,以及不用声明这个函数,使用的时候可以直接写。

这一点我们的老前辈c语言和c++11之前的c++就做不到,在这两位前辈的世界里,要把函数当做参数传递需要使用函数指针, 使用前要先声明函数

int callback(int val) {
return ++val;
} void test(int (*cb)(int)) {
int result = cb();
cout << result << endl;
} int main() {
test(callback);
return ;
}

test函数接受一个函数类型参数,callback函数就被作为这个参数传递。 这种写法没什么不好的,就是不够飘逸,就像金庸小说里的武功,这写法如同少林寺的七十二绝技,威力巨大, 却朴实无华,没有如凌波微步、北冥神功、天三六阳掌、天山折梅手这些武功那样吸引观众的眼球。

然而, 我们不能怪c和c++不够华丽, 毕竟这两门语言是上古时期的语言,是现在主流计算机语言们的祖宗, 从那个时代的角度去看待这样语言特性,已经是非常先进了。

就连之后的后起之秀java也没有做到这样好, java发展出了另一种丧心病狂的模式。 java8之前没有函数指针,没有匿名函数,更加没有lambda表达式。 在java中要实现这种编程模式只能使用类,可以是具名类, 也可以是匿名类, 在java的世界里,函数不能独立存在,它必须依赖于类。

于是,要把一个函数当参数传递, 只能传递一个类实例,这个类中再带上这个函数。

代码像这个样子

abstract class OnClickListener{
public void onClick() {
}
} protected void onCreate(Bundle savedInstanceState) {
btn.setOnClickListener(onclick);
}
OnClickListener onclick = new OnClickListener(){
@Override
public void onClick(View v) {
//do something
}
};

或者这样

abstract class OnClickListener{
public void onClick() {
}
}
protected void onCreate(Bundle savedInstanceState) {
btn.setOnClickListener(new OnClickListener(){
@Override
public void onClick(View v) {
//do something
}
});
}

原本几行代码可以搞定的事情却被写成了几十行,而且全是毫无意义的仪式性代码。怪不得人家常说java是用来写大型软件的,尼玛,几行代码硬生生被写成了几十行,这种写法能不大型吗

后来的java8支持lambda表达式,改善了这个问题,使java代码简洁了不少,但是那已经是java的第一个版本发布20年以后的事情了, 在这二十年里,不知道让多少java程序员写了多少无用的代码, 做了多少无用功。 但是谁叫它牛逼呢, 常年占据20%的编程语言份额, 死皮赖脸不知上进也没什么,吃老本也饿不死。 看看人家c#, 够上进吧, 还不是连自己的腰都摸不到。

说到这里,不得不提一样我们亲爱的世界上最好的语言php,php有匿名函数,但是这个匿名函数算不算lambda表达式呢?从广义的角度去理解,应该算,因为匿名函数和lambda表达式能实现同样的功能。从狭义的角度理解,因该不算,lambda表达式讲究的是飘逸潇洒,匿名函数太臃肿了,如果自认是lambda表达式, 我都替他不好意思。

php中的lambda表达式是这样写的

function test($callback) {
  $callback();
} function main() {
$data = [1,2,3,4,5];
  test(function() use($data){
    //dosomething
  })
}

main函数调用test函数传递的就是匿名函数(lambda表达式),这种写法和老式的javascript一样,虽然不优雅,但也挺和谐的。

且慢,这个匿名函数为什么带一个use关键字, 这个use关键字是什么鬼?

话说php的匿名函数带个use关键字这事吧, 我觉得有好有坏。 php的匿名函数默认是无法访问匿名函数自身作用域除this关键字引用的类实例以外的变量的,从上面的示例来说, 如果不使用use关键字,匿名函数中的代码将无法访问$data变量。 use关键字的作用就是导入这个变量,使匿名函数可以访问它。 所以, 使用不方便,就是use关键字的坏处, 函数用个变量, 还要特定的关键字导入, 坑了个爹。

然而,凡事要看两面,使用use关键字也能带来好处。用了use关键字,我们一眼就能看出这个匿名函素用了哪些外部变量,这对代码的可维护性起到一定的正面作用。不过就我个人来讲,还是非常讨厌这个关键字的,我要的是方便,可维护性什么的, 一边玩去,哥揍是这么任性。

最后呢,我们聊一聊lambda表达式的集大成者, kotlin。这门语言想必认识的人不多,用的人更少,不过它亲爹做的产品程序员们肯定是家喻户晓的, 如intellij idea、phpstorm、webstorm这些知名IDE都是, 这可都是除visual studio以外最好的集成开发环境了。至于它的干爹,想必知道的人更多,google,成立不到二十年,市值超过微软,智能手机系统安卓就是他家的,可惜他家的拳头产品google搜索引擎,在我们天朝无法使用。

kotlin的lambda表达式可以这样写

{}

就一个花括号,连常规的lambda表达式的括号和箭头都省了。 上面那个臃肿的java匿名类,换成kotlin就是这样子

protected void onCreate(Bundle savedInstanceState) {
btn.setOnClickListener({
    //dosomething
});
}

代码量瞬间减少了90%

有的同学要问了,这个lambda表达式如何接受参数

你可以这样

protected void onCreate(Bundle savedInstanceState) {
btn.setOnClickListener({ item ->
//dosomething
});
}

这个箭头, 不用的时候可以省略,用的时候可以带上,多么人性化。

所以,综上所述,论lambda表达式的易用性,kotlin排第二, 就没语言敢排第一。 另外,程序员在编程的时候, 一定要多用lambda,因为这是一种提高生产力的有力工具, 毕竟现在是二十一世纪了,要是再写上世纪80年代的代码,我都替他感到丢人。

lambda表达式杂谈的更多相关文章

  1. 你知道C&num;中的Lambda表达式的演化过程吗?

    那得从很久很久以前说起了,记得那个时候... 懵懂的记得从前有个叫委托的东西是那么的高深难懂. 委托的使用 例一: 什么是委托? 个人理解:用来传递方法的类型.(用来传递数字的类型有int.float ...

  2. Linq表达式、Lambda表达式你更喜欢哪个?

    什么是Linq表达式?什么是Lambda表达式? 如图: 由此可见Linq表达式和Lambda表达式并没有什么可比性. 那与Lambda表达式相关的整条语句称作什么呢?在微软并没有给出官方的命名,在& ...

  3. 背后的故事之 - 快乐的Lambda表达式(一)

    快乐的Lambda表达式(二) 自从Lambda随.NET Framework3.5出现在.NET开发者眼前以来,它已经给我们带来了太多的欣喜.它优雅,对开发者更友好,能提高开发效率,天啊!它还有可能 ...

  4. Kotlin的Lambda表达式以及它们怎样简化Android开发&lpar;KAD 07&rpar;

    作者:Antonio Leiva 时间:Jan 5, 2017 原文链接:https://antonioleiva.com/lambdas-kotlin/ 由于Lambda表达式允许更简单的方式建模式 ...

  5. java8中lambda表达式的应用,以及一些泛型相关

    语法部分就不写了,我们直接抛出一个实际问题,看看java8的这些新特性究竟能给我们带来哪些便利 顺带用到一些泛型编程,一切都是为了简化代码 场景: 一个数据类,用于记录职工信息 public clas ...

  6. 背后的故事之 - 快乐的Lambda表达式(二)

    快乐的Lambda表达式 上一篇 背后的故事之 - 快乐的Lambda表达式(一)我们由浅入深的分析了一下Lambda表达式.知道了它和委托以及普通方法的区别,并且通过测试对比他们之间的性能,然后我们 ...

  7. CRL快速开发框架系列教程二&lpar;基于Lambda表达式查询&rpar;

    本系列目录 CRL快速开发框架系列教程一(Code First数据表不需再关心) CRL快速开发框架系列教程二(基于Lambda表达式查询) CRL快速开发框架系列教程三(更新数据) CRL快速开发框 ...

  8. Lambda 表达式递归用法实例

    注意: 使用Lambda表达式会增加额外开销,但却有时候又蛮方便的. Windows下查找子孙窗口实例: HWND FindDescendantWindows(HWND hWndParent, LPC ...

  9. Spark中Lambda表达式的变量作用域

    通常,我们希望能够在lambda表达式的闭合方法或类中访问其他的变量,例如: package java8test; public class T1 { public static void main( ...

随机推荐

  1. CentOS安装keepalived

    Haproxy.Keepalived双主高可用负载均衡  1.安装keepalived yum install keepalived -y

  2. ubuntu安装和查看已安装

    说明:由于图形化界面方法(如Add/Remove... 和Synaptic Package Manageer)比较简单,所以这里主要总结在终端通过命令行方式进行的软件包安装.卸载和删除的方法. 一.U ...

  3. iOS 在下面 AOP 程序

    iOS 在下面 AOP 程序 概念 在软件业.AOP对于Aspect Oriented Programming缩写,手段:面向方面的编程.它是一种函数式编程张燕生风扇类型.通过这样一个技术方案功能的预 ...

  4. 【Loadrunner】初学Loadrunner——录制脚本、回放、以及优化

    一.脚本录制(录制) 打开Loadrunner > 选择创建/编辑脚本 > NewScript > 选择协议(单协议.多协议) > Strart Recording >选 ...

  5. 负载均衡软件LVS分析三&lpar;配置&rpar;

    LVS集群有DR.TUN.NAT三种配置模式,可以对www服务.FTP服务.MAIL服务等做负载均衡,下面通过搭建www服务的负载均衡实例,讲述基于DR模式的LVS集群配置. 一. Director ...

  6. &lbrack;leetcode-623-Add One Row to Tree&rsqb;

    Given the root of a binary tree, then value v and depth d, you need to add a row of nodes with value ...

  7. JSOIWC2019游记

    世除我WC...都去广二了qaq,就我还在nj ycs至少也去了pkuwc啊 这个JSOIWC2019的内容看起来很水,进入条件简单,但窝啥都不会,肯定垫底 内容清单: 1.26 上午听机房dalao ...

  8. XmlDocument根据节点的属性值获取节点

    string targetParm = string.Format("STUDENTS/STUDENT[@NO='{0}']", targetValue);//生成目标获取节点的参 ...

  9. Java面试题整理1

    Java基础部分 JDK和JRE有什么区别? JDK:Java Development Kit 的简称,java 开发工具包,提供了 java 的开发环境和运行环境.JRE:Java Runtime ...

  10. SpringInAction--自动化装配(显示装配之 java注解配置)

    Spring在配置时候有三种方案可选 1.在xml中进行显示配置 2.在java中进行显示配置 3.隐式的Bean发现机制和自动装配 今天学习的 第二种—— 在java中进行显示配置 场景: 尽管在很 ...