Lambda表达式,函数式接口,方法引用详解

本文是跟着宋红康老师讲解的视频做的笔记,视频地址:[尚硅谷]Java8新特性(Lambda表达式+Stream API+Optional类)_哔哩哔哩_bilibili

目录

什么是Lambda表达式

初见Lambda表达式

Lambda表达式写法

1. 无参,无返回值

2. 一个参数,无返回值

3. 数据类型可以省略,因为可由编译器推断得出,这称为“类型判断”

4. Lambda表达式如果只有一个参数,那么参数的小括号可以省略

5. Lambda有多个参数,有返回值

6. 当Lambda方法体只有一条语句,那么return和大括号都可以省略

总结:

函数式接口

四大函数式接口

方法引用

使用情形

使用格式

使用要求

1. 对象 : : 非静态方法​

2. 类 : : 静态方法​

3. 类 : : 非静态方法(有难度)​

构造器引用

1. 无参构造器​

2. 有参构造器​

数组引用​

总结


什么是Lambda表达式

Lambda是一个匿名函数,可以把lambda表达式理解为一段可以传递的代码

初见Lambda表达式

r1是一个Runnable接口的匿名实现类的对象,r2是使用Lambda表达式来创建对象,两个对象的效果一样,但是r2的代码明显更加简洁。这就是Lambda表达式。

化简为Lambda表达式的原则:能省就省。上图中Runnable接口只有一个需要实现的方法(即run方法),所以我们不需要写方法名就可以确定方法名(这其实就是函数式接口),由于r2是Runnable接口的对象,所以我们也可以确定类名。所以就化简为了( )→System.out.print("xxx");

再看个例子:

我们如何把上面的代码化简为Lambda表达式呢?可以看到这里仅仅多了两个参数,所以我们把两个参数加上即可:

  

我们还有一个更加简洁的版本:方法引用

方法引用我们后面会讲,先介绍Lambda表达式:

Lambda表达式写法

( xx,xx ) - > 方法体

左边:接口中抽象方法的形参列表

右边:重写接口中抽象方法的方法体

Lambda表达式的本质:作为接口的一个实例(对象)

表达式共有六种使用情况

1. 无参,无返回值

这是我们前面的Runnable接口的例子。

2. 一个参数,无返回值

不使用Lambda表达式:

使用Lambda表达式:

  

Lambda表达式的方法体中,如果只有一条语句,那么大括号写不写都行。

3. 数据类型可以省略,因为可由编译器推断得出,这称为“类型判断”

还是上面Consumer的例子,由于Consumer中的泛型为<String>,编译器可以推断出参数类型为String,所以我们不需要在Lambda表达式的形参列表中声明Stri

类型推断的另一个例子:

由于泛型中已经声明了String,我们就不需要在后面的<>中声明String了。

4. Lambda表达式如果只有一个参数,那么参数的小括号可以省略

还是Cosnumer的例子,省略小括号后:

5. Lambda有多个参数,有返回值

不使用Lambda表达式:

使用Lambda表达式:

由于类型推断,我们可以把o1和o2的类型省略。

如果实现的compare方法中有多个语句,那么我们不能省略方法体的大括号和return关键字:

6. 当Lambda方法体只有一条语句,那么return和大括号都可以省略

这就是上面的comparator例子:

总结:

Lambda表达式:(形参列表) - > { 方法体 }

本质:接口的实例对象。

**对于接口的要求:要求此接口必须只声明了一个抽象方法(这就是函数式接口)。**上面的例子中的接口,我们看源码的话会发现接口上都有一个注解@FunctionalInterface,表明这是一个函数式接口。这个注解仅仅是为了检验此接口是否为函数式接口,不加也行。

形参列表:参数类型可以省略;如果参数列表只有一个参数,那么小括号也可以省略,没有参数或者有一个以上的参数就不能省略小括号。

方法体:如果方法体只有一条执行语句,则可以省略大括号和return关键字。

函数式接口

只声明了一个抽象方法的接口。java不仅支持面向对象编程(OOP)也可以面向函数编程(OOF)

Lambda表达式就是一个函数式接口的对象。

以前用匿名实现类表示的现在都可以用Lambda表达式来写。

四大函数式接口

四大函数式接口指的是Consumer、Function、Predicate、Supplier,位于java.util.function包下

第一种:Consumer<T>:消费型接口      void accept(T t);

第二种:Supplier<T>:供给型接口      T get();

第三种:Function<T,R>:函数型接口 ,T为自变量,R为因变量     R apply(T t);

第四种:Predicate<T>:断言型接口 boolean test(T t)

消费型接口示例:

断言型接口示例:

定义一个方法,第二个参数为断言型接口,想要实现的功能为:基于某种规则pre,来筛选list中符合规则的字符串。

筛选规则我们可以通过Lambda表达式来实现:

方法引用

使用情形

当要传递给Lambda表达式方法体的操作,已经有实现的方法了,此时可以使用方法引用。

方法引用本质上就是Lambda表达式,即方法引用也是函数式接口的实例。

使用格式

类(或对象) : : 方法名

参数列表都不用写了

使用要求

对于下面的情况1和情况2:要求接口中的抽象方法的形参列表和返回值,与方法引用的方法的形参列表和返回值都相同。而且本来我们Lambda表达式的方法体代码中正好用到了方法引用的方法,我们就可以使用方法引用来替换Lambda表达式。

对于情况3,可以不满足上面的描述,具体往下看。

方法引用一共分为如下三种情况

1. 对象 : : 非静态方法

分析:Lambda表达式中的方法体为System.out.println(str),然后调用con1的accept方法。我们发现PrintStream类中的println方法和accept方法参数列表和返回值都一样,我们可以理解为println方法已经实现了accept方法(传递给Lambda表达式方法体的操作,已经有实现的方法了),所以我们可以使用方法引用

再来看一个例子:

觉得难以理解没关系,这只是一种新的语法,逻辑上确实难以理解,用多了就懂了。

2. 类 : : 静态方法

再来一个示例:

3. 类 : : 非静态方法(有难度)

我们发现compare的两个参数,第一个参数可以当做调用者调用String类的compareTo方法,第二个参数仍然作为参数。这时就可以使用类::非静态方法的形式。注意我们仍然不写compareTo的参数列表。

再看个例子:

只有一个参数的时候,也可以用类::非静态方法,apply方法唯一的一个参数当做getName方法的调用者。

构造器引用

1. 无参构造器

可以看到Employee类的无参构造方法,和get方法一样没有参数,当new 无参构造方法( )的时候会返回一个Employee对象。当我们Lambda表达式的方法体中调用了new Employee( )的时候,就可以使用方法引用Employee : : new 。

2. 有参构造器

我们同样不能在方法引用上加参数,因为参数可以通过apply传递。

再来看一个两个参数的构造器:

数组引用

返回值为一个数组对象,其他的和构造器引用类似。

把数组看做一个特殊的类,则写法与构造器引用一致。

总结

可以不会写,但是要能看懂,因为很多源码使用了Lambda表达式或者方法引用。

猜你喜欢

转载自blog.csdn.net/qq_45835078/article/details/120578778