lambda表达式_一起学习Java8之Lambda表达式

Lambda表达式,既然叫做表达式,那么它要表达式的是什么呢?实际上Lambda表达的是一个函数,这个函数只有参数列表和函数体,所以Lambda表达式也被叫做匿名函数。

1 Lambda表达式组成

Lambda由三部分组成,分别是参数列表、箭头、函数体

参数列表

  1. 和普通函数一样,Lambda也有参数列表,且表达方式相同,如:(ParamType1 param1, ParamType2 param2, ...)。
  1. 可以省略参数列表参数类型,如(param1, param2, ...)。
  1. 如果参数列表只有一个,且省略了参数类型,可以省略(),如param1。
  1. 参数列表没有参数,()不能省略。

箭头

Lambda表达式的参数列表后紧跟关的是箭头,如->。

函数体

  1. 和普通函数一样,Lambda也有函数体,如{ System.out.println("hello world!")}。
  1. 如果函数体只有一条语句,可以省略{},如System.out.println("hello world!")}。
  1. 如果函数体只有一条语句,且函数有返回值,要省略return关键字。

举例:

  1. 完整参数列表
385eb6c67bbc735f85e156e724dbb3cd.png
  1. 参数列表省略参数类型
4791a885196c5434b12e7c4e94a3388f.png

参数列表省略()

49affc564f405cb7d653f546bf80cca9.png

参数列表没有参数

c50a6f1a16ae0ed9400eab904d1e1ddc.png

函数体只有一条语句,可以省略{}

be8062fe827c9b7b3e852f94c050f832.png

函数体只有一条语句,且函数有返回值,省略return关键字

6214aad820eb17ef1dc94d5398ebefec.png

通过上面的例子,不难看出Lambda表达式可以被一个对象接收,所以Lambda表达式也能看做是一个对象,相当于匿名类,而接收Lambda表达式的对象类型也被统称为函数式接口。

2 函数式接口

通过对2.1中接收Lambda表达式的对象的类型的研究,我们可以发现,这些接口都有一个共同特征,那就是这些接口中只有一个抽象方法。所以对于函数式接口的定义也就是:只有一个抽象方法的接口就是函数式接口。Lambda表达式只能作用在函数式接口上。

@FunctionalInterface注解,一般的函数式接口,都由@FunctionalInterface注解注释,该注释用于表示该接口就是函数式接口,也能用于校验当前接口是否满足函数式接口的定义。要注意,并不是说只有使用了@FunctionalInterface注解的接口才是函数式接口,只要满足函数式接口的定义的接口都是函数式接口。

3 如何使用Lambda表达式

第1节中,我们用了几个Lambda表达式,并且用一个变量接收了它们,那么,它们该如何工作呢?

以下面这个为例:

b6385b78eb7448c09d842f1118e4e346.png

我们用Runnable r变量接收了一个Lambda表达式,那么r是一个Runnable接口类型的对象(多态),由于Runnable接口中只有一个抽象方法run(),所以该对象能调用的方法也就是这个run()方法。前面我们也说过,Lambda表达式表达的是一个函数,在这个例子中,该Lambda表达式表达的就是run()这个方法(函数)了。所以我们要使这个Lambda正常工作只需要调用这个run()方法即可。

e8d92c91c20349a79228154a3dabe069.png

同理,对于

166f4dee0146898e782238d9df822061.png

我们同样只需要调用Comparator接口中的抽象方法即可:

8f604173d8b053bcc42341709890186e.png

至于上面的Predicate predicate = a -> a > 3;,要如何使用这里不再赘述。

4 类型推断

正如我们上面所说的,Lambda表达式可以省略参数列表中的参数类型,那么如果省略了参数类型,Lambda是如何知道参数是什么类型的呢?Lambda表达式中用到的就是类型推断!

57154441ee51c7762856dc4e7d53fe20.png

上例中,使用了Comparator接口,下面是Comparator接口的定义,结合上例,Comparator中泛型的类型是T是Integer,所以compare的参数类型的T也就Integer。

6e4c7fe19003af27ebd597150a3aa5bb.png

这就是在Lambda中使用到的类型推断。

5 引用外部变量

这里我们要明确一个概念外部变量,外部变量指定的是不属性于当前函数或者类的变量,比如Lambda表达式引入一个没有在Lambda表达式中定义的变量,匿名类引用一个没在该类中定义的变量,这些变量都属性外部变量。

使用匿名类,在Java 1.8之前引用的外部变量必须是final类型的,在Java 1.8之后,外部变量可以不用使用final关键字,但是引用的外部变量不允许被改变。

Lambda相当于匿名类,所以对于Lambda表达式要使用外部变量也有同样的限制。

f88e7bc318d9ce6bdeb08008bb621e98.png

所以在Lambda中有引用到外部变量,该外部变量是不允许被改变的。

6 默认函数式接口

在JDK中也默认提供了一些常用的函数式接口,这些接口在java.util.function包下,这里列举一些基本的函数式接口:

函数式接口函数描述符参数返回类型示例(在集合中的应用)

f8324083d3d323e1726845d6296deb2e.png

上述4个函数式接口,是最常用的几个函数式接口。

关于装箱拆箱

如Predicate中的T是泛型,泛型不能接收基本类型,但是使用包装类型会增加内存和计算开销,所以对于基本类型Java 8中也提供了对应的函数式接口,基本类型的函数式接口主要有:

函数式接口函数描述符

66a4af7a77fb14860749e75ebea212fb.png

更多函数式接口:

关于常用函数式接口总结:

以int类型为例的函数式接口如上,其他类型类同 。要注意,基本类型的函数式接口只针对常用的long、int及double。其他基本类型没有对应的函数式接口。

87f8f9603be0b044b58b307c4a1fe297.png
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值