我们知道使用Lambda表达式的前提是需要有函数式接口。
而Lambda使用时不关心接口名,抽象方法名,只关心抽 象方法的参数列表和返回值类型。
因此为了让我们使用Lambda方便,JDK提供了大量常用的函数式接口。
它们主要在 java.util.function 包中。下面是最常用的几个接口。
1. Supplier接口
2. Consumer接口
3. Function接口
4. Predicate接口
1、Supplier接口
java.util.function.Supplier 接口,它意味着"供给" , 对应的Lambda表达式需要“对外提供”一个符合泛型类型的对象数据。
供给型接口,通过Supplier接口中的get方法可以得到一个值,无参有返回的接口。
使用Lambda表达式返回数组元素最大值
使用 Supplier 接口作为方法参数类型,通过Lambda表达式求出int数组中的最大值。
注:接口的泛型请使用 java.lang.Integer 类。
代码示例
2、Consumer接口
java.util.function.Consumer接口则正好相反,它不是生产一个数据,而是消费一个数据,其数据类型由泛型参数决定。
使用Lambda表达式将一个字符串转成大写和小写的字符串
Consumer消费型接口,可以拿到accept方法参数传递过来的数据进行处理, 有参无返回的接口。
代码示例:
默认方法:andThen
如果一个方法的参数和返回值全都是 Consumer 类型,那么就可以实现效果:消费一个数据的时候,首先做一个操作,然后再做一个操作,实现组合。
而这个方法就是 Consumer 接口中的default方法 andThen 。
下面是JDK的源代码:
注: java.util.Objects 的 requireNonNull 静态方法将会在参数为null时主动抛出
NullPointerException 异常。这省去了重复编写if语句和抛出空指针异常的麻烦。
要想实现组合,需要两个或多个Lambda表达式即可,而 andThen 的语义正是“一步接一步”操作。
例如两个步骤组合的情况:
运行结果将会首先打印完全小写的hello,然后打印完全大写的HELLO。
当然,通过链式写法可以实现更多步骤的组合。
3、Function接口
java.util.function.Function<T,R> 接口用来根据一个类型的数据得到另一个类型的数据,前者称为前置条件,后者称为后置条件。有参数有返回值。
代码示例:
Function转换型接口,对apply方法传入的T类型数据进行处理,返回R类型的结果,有参有返回的接口。使用的场景:将 String 类型转换为 Integer 类型。
使用Lambda表达式将字符串转成数字
默认方法:andThen
Function 接口中有一个默认的 andThen 方法,用来进行组合操作。JDK源代码如:
该方法同样用于“先做什么,再做什么”的场景,和 Consumer 中的 andThen 差不多:
第一个操作是将字符串解析成为int数字,第二个操作是乘以10。
两个操作通过 andThen 按照前后顺序组合到了一起。
请注意,Function的前置条件泛型和后置条件泛型可以相同。
4、Predicate接口
有时候我们需要对某种类型的数据进行判断,从而得到一个boolean值结果。
这时可以使用java.util.function.Predicate 接口。
使用Lambda判断一个人名如果超过3个字就认为是很长的名字
对length方法的参数T进行判断,返回boolean类型的结果。用于条件判断的场景:
条件判断的标准是传入的Lambda表达式逻辑,只要名称长度大于3则认为很长。
4.1 默认方法:and
既然是条件判断,就会存在与、或、非三种常见的逻辑关系。
其中将两个 Predicate 条件使用“与”逻辑连接起来实现“并且”的效果时,可以使用default方法 and 。其JDK源码为:
如果要判断一个字符串既要包含 掘,又要包含金;
4.2 默认方法:or
使用Lambda表达式判断一个字符串中包含掘金或者包含6月
与 and 的“与”类似,默认方法 or 实现逻辑关系中的“或”。
JDK源码为:
如果希望实现逻辑“字符串包含掘金或者包含6月”,那么代码只需要将“and”修改为“or”名称即可,其他都不变:
4.3 默认方法:negate
使用Lambda表达式判断一个字符串中不包含摆烂
“与”、“或”已经了解了,剩下的“非”(取反)也会简单。
默认方法 negate 的JDK源代码为:
代码演示: