jdk8中提供了几个新特性,其中一个比较受瞩目的就是Lambda表达式。
Lambda也是就函数式编程,主要替代了之前版本的匿名内部类的的实现。下面看一个例子:
在jdk8之前,如果想实现一个线程,可以使用如下方式:
使用Lambda表达式之后,我们可以这些编写:
简单的一句话,代替了之前看似复杂的实现,至于所说的可读性,如果明白这么是怎么回事,那么可读性提高,不明白,就没有所谓的可读性。
Lambda语法
从上面的例子可以看出来,lambda语法分为2部分,使用"->"进行分割,前面一部分 () 就是参数列表,后面一部分就是执行方法体。表示如下:
( 参数 )->{ 方法体 };
使用规则
前面主要讲述了Lambda表达式能干什么,这里会存在一个疑问,如果一个接口其中有多个方法,能使用Lambda表达式么?答案是无法使用,这里还引入了一个概念,想要使用Lambda表达式,接口必须是函数式接口(其实就是拥有一个方法的接口)。可以使用注解@FunctionalInterface进行规范。
当增加了 @FunctionalInterface 注解,就会提示只能存在一个方法。
Lambda的使用
定义一个函数式接口:
使用Lambda表达式可以这样实现:
如果是多个参数:
使用方式其实很简单,只要了解了lambda是干什么的和其语法接口,就知道需要怎么进行书写。也能存在多个参数\无返回值,无参数\有返回值等情况。
当只有一个参数的时候,参数中的() 可以省略,当代码体只有一行的时候 return 关键字也可以省略。
JDK主要内置函数式接口
为了让开发者书写更加方便,jdk提供了很多函数式接口让我们使用,基本满足了日常的使用,其中主要的四个接口如下:
接口 | 方法 | 说明 |
Consumer<T> | void accept(T t); | 消费型接口,参数泛型,返回值为空 |
Supplier<T> | T get(); | 供给型接口,参数为空,返回值为泛型 |
Function<T, R> | R apply(T t); | 函数型接口,参数泛型,返回值为泛型 |
Predicate<T> | boolean test(T t); | 断言型接口,参数泛型,返回值为boolean |
从上面的提供,可以看出来,针对不同的情况,采用不同的内置函数接口即可,JDK还提供了其他的函数式接口,基本都是从这四个接口演变过来的:
下面随便写一个例子,使用BiFunction函数式接口,他的apply 2个泛型参数,返回泛型参数
方法引用和构造器引用
除了之前讲述了Lambda表达式的基本使用,还有两种方式的使用,方法引用和构造器引用(不过应该都算是方法引用,构造方法也算是一个特殊的方法)
一、方法引用
所谓方法引用其实就是把Lambda表达式写成 对象\类::方法名\静态方法名。
当时要注意两点:
① 方法\静态方法必须与函数式接口中的方法参数和返回值相同
② 当第一个参数是方法调用者,第二个参数是方法参数的时候,可以写成 ClassName::实例方法
下面举几个例子:
1、对象::方法名
可以见到,myFunction1和myFunction2 都是使用Lambda表达式进行表示,只不过myFunction2使用了方法引用而已。
2、类::静态方法名
3、类::非静态方法
这时候,可以看到函数式接口第一个参数传入的是 Modle对象,第二个参数参入的是一个string字符串,并且方法体重重,使用第一个参数调用方法,第二个参数是方法的参数。
二、构造器引用
构造方法返回值是固定的,所以这里的规则就是,函数式接口的方法参数和构造方法参数相同即可。
这里函数式接口返回值为泛型,也可以定义为Model,但是如果定义其他类型就不可以了,是可以理解的,因为所谓的构造器引用就是方法引用的特殊方式,而方法引用中规定参数和返回值必须相同。
以上就是对Lambda表达式的介绍,下面总结一下:
1、Lambda表达式就是一种函数式编程的写法,解决了以前匿名内部类书写的繁琐问题
2、Lambda表达式实现的接口,必须是函数式接口(只有一个方法)
3、JDK本身提供了很多函数式接口,基本满足日常开发(java.util.function)
4、除了普通写法,可以使用方法引用、构造器引用的写法