这篇文章重点不在于如何去学习Lambda表达式,因为已经有很多那样的文章了。我想要描述的,是如何更迅速的去阅读和运用Lambda表达式。

1. 必须知道的知识

首先你要知道:

Lambda表达式都是通过接口来传递的。

换言之,看到Lambda表达式,你第一反应应该是,这个方法的参数一定是一个接口!

再者:

Lambda表达式对应的接口,只有一个接口方法。

举个例子:

Comparator.comparing(integer -> integer)

抛开Lambda表达式本身,此时你需要知道,Comparator.comparing方法需要传入一个接口,而接口只有一个方法。

2. 开始阅读

假设你不知道Comparator.comparing里面是啥接口,也不知道他的入参和返回值是什么。

还是上面的例子:

Comparator.comparing(integer -> integer+1)

请记住这样的规律:

对于 integer -> integer,我们拆分为三个部分:

第一部分: integer

第二部分: ->

第三部分: integer+1

其中,

第一部分

是入参,是一个变量;

第二部分

-> 表示 comparing方法中的接口;

第三部分

是接口中唯一的那个方法的方法体,有两种可能:

  • 返回值(此时return可以忽略不写);

  • 是一个表达式(表达式可能会返回一个值,也可能没有返回值);

    在这个例子中,第三部分是 integer+1 ,此时我们无法判断 integer+1 是用作返回值,还是在执行一个变量+1的表达式。没关系,理解到这一部分,已经足够了。如果需要知道,就需要查看文档,或者通过IDE看一下有没有返回值了。

总结一下这个过程,可以这样表示:

   x           ->          doSomething
一个参数    经过某个接口     接口的方法做的操作(接口中的方法的方法体)

类似的:

 (x,y)           ->               {doSomething}
2个参数x,y    经过了某个接口      接口的方法做的操作(接口中的方法的方法体)

这个过程,我参考了《Java 8函数式编程》。书本里的描述写的可能比我更好。

3. 常用的函数接口及其规律

接触Lambda表达式的时候,看着一堆的箭头经常会觉得晕。

不知道为什么这个方法要传Function?

为什么那个又要传一个Consumer?

为什么这个接口有一个入参,那个接口有两个入参?

其实这主要还是自己不熟悉常用的函数接口造成的。

为了便于日常的使用,有必要记住常见的接口函数以及了解他们的一般规律。

常见函数接口及其作用

| 分类 | 参数/返回值 | 接口方法 | 作用 |
| :——– | :————– | :————– | :————————————— |
| Function | 有入有出 | apply或者以apply开头 | 用入参,经过操作,获取xxx |
| Consumer | 只入 | accept | 消费者,消费入参 |
| Predicate | 有入有出(只boolean出) | test | 断言,判断,根据入参来判断true/false |
| Operator | 有入有出 | apply或者以apply开头 | 1. Function的特例,部分接口继承自Function(部分是自定义的),所以也表示“从…经过操作,获取…”;
2.入参和返回值类型一致。 |
| Supplier | 只出 | get或者以get开头 | 供应者,工厂,提供xxx |

常用的函数接口分类

| 特征 | Second Header | 例子 |
| ——- | :————————– | :————— |
| Bi开头 | 表明该接口有两个入参 | BidFunction |
| 以基本类型开头 | 要么是返回这种基本类型,要么是只接收这种基本类型的入参 | DoublePredicate |
| 以To开头 | 表示返回值是这种类型 | ToDoubleFunction |

下面来尝试一下:

comparingDouble(ToDoubleFunction<? super T> keyExtractor)

对于上面的代码,来猜测一下ToDoubleFunction接口的入参和返回值。

因为是以ToDouble开头,所以返回值是double;

因为只有一个泛型,所以入参只有一个;

反过来,如果你是comparingDouble()方法的设计者。

此时你知道你需要入参,同时需要返回一个Double值,观察上面的表格,你会发现,也只能用Function或者Operator了。

如果你又觉得,你的入参和出参的类型是不一致的,那么肯定要排除掉Operator了,所以你只能从众多的Function中挑选一个。

所以,我觉得提早知道入参的个数和返回值类型,熟悉什么时候需要什么接口函数,这有助于我们对方法本身的理解,也能提高我们编写代码的效率。