前往小程序,Get更优阅读体验!
立即前往
首页
学习
活动
专区
工具
TVP
发布
社区首页 >专栏 >神奇的Lambda

神奇的Lambda

作者头像
用户1260737
发布2019-05-24 20:42:19
7010
发布2019-05-24 20:42:19
举报
文章被收录于专栏:趣谈编程

多变的需求

一天傍晚,慧能把一尘叫到自己的身旁。

慧能

一尘啊,为师想知道咱们班哪些人身高170?你可以帮我写一个程序吗?

这还不简单?

一尘

只见一尘飞速的写下了下面的代码

涛声依旧注:Student 类有姓名、身高和体重等属性。

慧能

那我如果想知道身高大于165的同学呢?

那就复制一份刚才的代码然后把170改成165.

一尘

慧能

难道对于每一个身高都要这样重复的复制和修改吗?

这个。。。

一尘

慧能

提醒你一下:抽象

哦,我知道了,我可以用一个变量来代替这个你要求的身高值。

一尘

立刻一尘写下了如下代码

慧能

嗯嗯,不错,孺子可教也。

嘿嘿!

一尘

慧能

那我现在想找那些体重过百的同学怎么办呢?

这次一尘吸取上次的教训,直接用一个变量来表示体重了。只见一尘快速写下了如下代码。

慧能

那如果我想知道哪些同学考试前十呢?如果我想知道哪些同学的家在陕西呢?。。。

啊! 好多需求啊,这又得粘贴复制之前的方法,然后然后再稍微修改一下。

一尘

慧能

所以说你需要写出一个通用的方法,可以应对我的这些变化。

这可怎么搞,这不能再搞一个x吧。

一尘

只见师傅慢慢悠悠地说了两个字:

抽象

又是抽象,这个弟子不才,还请师傅指教。

一尘

慧能

Java中的多态是什么?接口又是什么?

既然你想对我不同的行为进行抽象,而方法代表着行为,那么你就需要用到抽象方法。

你可以在一个接口中声明一个抽象方法,然后再不同的实现类中去实现这个方法。这样不就进行了统一了吗。

说着只见师傅写下了如下代码

然后上层在使用的时候可以这样使用

此时的抽象方法 test 的实现是由调用你写的通用方法 findEligibility 的人来实现的。

test方法的实现被放在了一个对象中了,这个对象是匿名的。也就是Java中的匿名类的实例。

这个对于Java开发者很是自然,test方法被放在了类里面,然后类的引用被传递到 findEligibility() 之中。这样就可以使用引用来调用方法了。

哦,对哦,可以定义接口,然后根据不同的需求进行不同的实现,而我写的方法却不用改动。这个接口就相当于抽象后的 x变量。

一尘

慧能

说的没错。

慧能

一尘,你有没有发现我刚才写的代码很啰嗦,代码模板很多。

嗯嗯,是啊,但是我们一直以来都是这样写的呀,难道还要更好的写法?

一尘

Lambda表达式

慧能

对,没错,在Java8中引入了Lambda表达式,我们可以使用它使得代码变得更加的简洁

我们首先看一下我们上面的代码的问题在哪里。

很明显的可以看出它比较笨重,占的空间比较大,编写起来也耗时(因为要写很多模板代码),并且不能够直接看出你想表达的东西(不够易读,很繁琐)

那么我们可不可以直接把方法中的代码(核心代码也就是 student.getHeight() > 170)直接传递给 findEligibility() 方法呢,在之前是不行的,因为我们的方法必须依附于类而进行传递。

但是在Java 8 中这个愿望可以实现了,Java8允许我们直接传递方法,而不用把方法放在类里面进行传递了。我们可以通过Lambda 表达式实现它。

那么我们应该如何用Lambda表达式实现它呢?我们可以这样写。

当你看到这样的改变后会想,这Lambda到底什么鬼?怎么这样写,但是对比一下和之前的写法,又感觉确实代码简洁了许多。

看不懂没关系,我们来解释一下这句Lambda表达式的意思吧。

首先是Lambda参数,细心的你可能已经发现了,这个参数就是 之前写的 test 方法的参数。

箭头把参数和主体分开来了

然后就是Lambda主体,其实就是test方法体里面的东西。

聪明的你可能已经发现,其实上面的Lambda表达式就是简化版的 test 方法,并且这个方法可以直接传递给 findEligibility() 方法,不用依附于某一个类或者对象上。

从演变过程来看,Lambda确实去掉了很多不必要的信息,保存了最核心的东西,这样一来,代码就会更接近你想表达的东西,也就更加简洁了。

在演变的第一步,我们让方法摆脱了对类的束缚,这一改变是巨大的。从此我们可以将方法块直接传递给方法中的参数了。

这样方法就已经脱离了类的存在而直接存在了。

逻辑严谨的同学可能也能够看出,这里的这个Lambda表达式,其实就是我们之前写的接口中的抽象方法的具体实现。

如果你的Lambda表达式不符合test方法的声明时,编译器就会报错,比如:

test只有一个参数。这里的Lambda有两个,与之不符。

函数式接口

还记得上面写的接口Predicate吗?

它就是一个函数式接口。

那什么是函数式接口呢?其实就是只含有一个抽象方法的接口就是函数式接口。

在新的API设计中,用注解@FunctionalInterface来表明某一个接口是函数式接口

函数式接口本质还是一个接口,它里面有一个抽象方法,规定了方法的行为特征。

其实在我们平时使用中,有很多情况我们会使用同样的接口,所以Java 8 设计者给我们提供好了几个常用的函数式接口,比如常见的 Predicate、Consumer和Function。

Predicate

这个函数式接口应该不用多说,其实和我们例子中的Predicate一样,它定义了一个 test的抽象方法,用来接受一个参数T,然后返回一个布尔值。

只不过Java8设计者这个Predicate支持了泛型。

Consumer

这个函数式接口接受一个泛型T,没有返回值,它想表达的意思就是当你需要执行一类操作时,这类操作接受一个参数,但是没有返回值,执行一系列操作就完事了,这类操作很适合Consumer。

比如说你接受一个int值,然后打印它,这时候你就可以使用Consumer。

Lambda控制的是行为,在这里也就是我要如何处理这个2

Function

Fuction 函数式接口声明了一个 apply 的方法,它接受一个泛型T,然后返回一个泛型R。当你需要接受某一个东西,并且还需要返回某个东西的时候可以使用Fuction.

比如你想实现输入一个字符串,返回一个字符串的长度,那么就可以这样。

原来Lambda这么强大

一尘

慧能

嗯嗯,灵活的使用它可以编写出优雅的代码。关于Lambda具体实战,以后再和你分享吧。

参考:

《Java8实战》

《码农翻身》

千千万万的公众号中

能被你识别都是缘分

本文参与 腾讯云自媒体同步曝光计划,分享自微信公众号。
原始发表:2019-05-23,如有侵权请联系 cloudcommunity@tencent.com 删除

本文分享自 趣谈编程 微信公众号,前往查看

如有侵权,请联系 cloudcommunity@tencent.com 删除。

本文参与 腾讯云自媒体同步曝光计划  ,欢迎热爱写作的你一起参与!

评论
登录后参与评论
0 条评论
热度
最新
推荐阅读
领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档