1.1 目标
1.2 内置函数式接口来由来
我们知道使用Lambda表达式的前提是需要有函数式接口。而Lambda使用时不关心接口名,抽象方法名,只关心抽
象方法的参数列表和返回值类型。因此为了让我们使用Lambda方便,JDK提供了大量常用的函数式接口。
1.3 常用内置函数式接口介绍
它们主要在 java.util.function 包中。下面是最常用的几个接口。
1. Supplier接口

- Consumer接口
1.4 Supplier接口
java.util.function.Supplier 接口,它意味着”供给” , 对应的Lambda表达式需要“对外提供”一个符合泛型类 型的对象数据。

供给型接口,通过Supplier接口中的get方法可以得到一个值,无参有返回的接口。
使用Lambda表达式返回数组元素最大值
使用 Supplier 接口作为方法参数类型,通过Lambda表达式求出int数组中的最大值。提示:接口的泛型请使用
java.lang.Integer 类。
代码示例:

package com.itheima.demo03functionalinterface;import java.util.Arrays;import java.util.function.Supplier;public class Demo02Supplier {// 使用Lambda表达式返回数组元素最大值public static void main(String[] args) {System.out.println("开始了");printMax(() -> {int[] arr = {11, 99, 88, 77, 22};// 先排序,最后就是最大的Arrays.sort(arr); // 升序排序return arr[arr.length - 1];});}public static void printMax(Supplier<Integer> supplier) {int max = supplier.get();System.out.println("max = " + max);}}
1.5 Consumer接口
java.util.function.Consumer 接口则正好相反,它不是生产一个数据,而是消费一个数据,其数据类型由泛 型参数决定。

使用Lambda表达式将一个字符串转成大写和小写的字符串
Consumer消费型接口,可以拿到accept方法参数传递过来的数据进行处理, 有参无返回的接口。基本使用如:

package com.itheima.demo03functionalinterface;import java.util.function.Consumer;public class Demo03Consumer {// 使用Lambda表达式将一个字符串转成大写的字符串public static void main(String[] args) {System.out.println("开始啦");printHello((String str) -> {System.out.println(str.toUpperCase());});}public static void printHello(Consumer<String> consumer) {System.out.println("aaa");consumer.accept("Hello World");}}
默认方法:andThen
如果一个方法的参数和返回值全都是 Consumer 类型,那么就可以实现效果:消费一个数据的时候,首先做一个操
作,然后再做一个操作,实现组合。而这个方法就是 Consumer 接口中的default方法 andThen 。下面是JDK的源代
码:

备注: java.util.Objects 的 requireNonNull 静态方法将会在参数为null时主动抛出
NullPointerException 异常。这省去了重复编写if语句和抛出空指针异常的麻烦。
要想实现组合,需要两个或多个Lambda表达式即可,而 andThen 的语义正是“一步接一步”操作。例如两个步骤组合
的情况:

package com.itheima.demo03functionalinterface;import java.util.function.Consumer;public class Demo04ConsumerAndThen {// 使用Lambda表达式先将一个字符串转成小写的字符串,再转成大写public static void main(String[] args) {System.out.println("开始啦");printHello((String str) -> {System.out.println(str.toLowerCase());}, (String str) -> {System.out.println(str.toUpperCase());});}public static void printHello(Consumer<String> c1, Consumer<String> c2) {System.out.println("aa");String str = "Hello World";// c1.accept(str);// c2.accept(str);c2.andThen(c1).accept(str);}}
运行结果将会首先打印完全大写的HELLO,然后打印完全小写的hello。当然,通过链式写法可以实现更多步骤的组 合。
1.6 Function接口
java.util.function.Function 接口用来根据一个类型的数据得到另一个类型的数据,前者称为前置条件, 后者称为后置条件。有参数有返回值。

使用Lambda表达式将字符串转成数字
Function转换型接口,对apply方法传入的T类型数据进行处理,返回R类型的结果,有参有返回的接口。使用的场景
例如:将 String 类型转换为 Integer 类型。

package com.itheima.demo03functionalinterface;import java.util.function.Function;public class Demo05Function {// 使用Lambda表达式将字符串转成数字public static void main(String[] args) {System.out.println("开始");getNumber((String str) -> {int i = Integer.parseInt(str);return i;});}public static void getNumber(Function<String, Integer> function) {System.out.println("aa");Integer num1 = function.apply("10");System.out.println("num1 = " + num1);}}
默认方法:andThen
Function 接口中有一个默认的 andThen 方法,用来进行组合操作。JDK源代码如:

该方法同样用于“先做什么,再做什么”的场景,和 Consumer 中的 andThen 差不多:

package com.itheima.demo03functionalinterface;import java.util.function.Function;public class Demo06FunctionAndThen {// 使用Lambda表达式将字符串转成数字, 第二个操作将这个数字乘以5public static void main(String[] args) {getNumber((String str) -> {return Integer.parseInt(str);}, (Integer i) -> {return i * 5;});}public static void getNumber(Function<String, Integer> f1, Function<Integer, Integer> f2) {System.out.println("aa");// Integer num = f1.apply("6");// Integer num2 = f2.apply(num);Integer num2 = f1.andThen(f2).apply("6");System.out.println("num2 = " + num2);}}
第一个操作是将字符串解析成为int数字,第二个操作是乘以10。两个操作通过 andThen 按照前后顺序组合到了一 起。
请注意,Function的前置条件泛型和后置条件泛型可以相同。
1.7 Predicate接口
有时候我们需要对某种类型的数据进行判断,从而得到一个boolean值结果。这时可以使用
java.util.function.Predicate 接口。 
使用Lambda判断一个人名如果超过3个字就认为是很长的名字
对test方法的参数T进行判断,返回boolean类型的结果。用于条件判断的场景:

package com.itheima.demo03functionalinterface;import java.util.function.Predicate;public class Demo07Predicate {// 使用Lambda判断一个人名如果超过3个字就认为是很长的名字public static void main(String[] args) {System.out.println("开始啦");isLongName((String name) -> {return name.length() > 3;});}public static void isLongName(Predicate<String> predicate) {System.out.println("aa");boolean isLong = predicate.test("迪丽热巴");System.out.println("是否是长名字: " + isLong);}}
条件判断的标准是传入的Lambda表达式逻辑,只要名称长度大于3则认为很长。
默认方法:and
既然是条件判断,就会存在与、或、非三种常见的逻辑关系。其中将两个 Predicate 条件使用“与”逻辑连接起来实
现“并且”的效果时,可以使用default方法 and 。其JDK源码为:

使用Lambda表达式判断一个字符串中即包含W,也包含H
使用Lambda表达式判断一个字符串中包含W或者包含H
使用Lambda表达式判断一个字符串中即不包含W
如果要判断一个字符串既要包含大写“H”,又要包含大写“W”,那么:
package com.itheima.demo03functionalinterface;import java.util.function.Predicate;public class Demo08Predicate_And_Or_Negate {// 使用Lambda表达式判断一个字符串中即包含W,也包含H// 使用Lambda表达式判断一个字符串中包含W或者包含H// 使用Lambda表达式判断一个字符串中不包含Wpublic static void main(String[] args) {test((String str) -> {// 判断是否包含Wreturn str.contains("W");}, (String str) -> {// 判断是否包含Hreturn str.contains("H");});}public static void test(Predicate<String> p1, Predicate<String> p2) {// String str = "Hello orld";// boolean b1 = p1.test(str);// boolean b2 = p2.test(str);// if (b1 && b2) {// System.out.println("即包含W,也包含H");// }// 使用Lambda表达式判断一个字符串中即包含W,也包含HString str = "Hello World";boolean b = p1.and(p2).test(str);if (b) {System.out.println("即包含W,也包含H");}}}
默认方法:or
使用Lambda表达式判断一个字符串中包含W或者包含H
与 and 的“与”类似,默认方法 or 实现逻辑关系中的“或”。JDK源码为:

如果希望实现逻辑“字符串包含大写H或者包含大写W”,那么代码只需要将“and”修改为“or”名称即可,其他都不变:
package com.itheima.demo03functionalinterface;import java.util.function.Predicate;public class Demo08Predicate_And_Or_Negate {// 使用Lambda表达式判断一个字符串中即包含W,也包含H// 使用Lambda表达式判断一个字符串中包含W或者包含H// 使用Lambda表达式判断一个字符串中不包含Wpublic static void main(String[] args) {test((String str) -> {// 判断是否包含Wreturn str.contains("W");}, (String str) -> {// 判断是否包含Hreturn str.contains("H");});}public static void test(Predicate<String> p1, Predicate<String> p2) {// String str = "Hello orld";// boolean b1 = p1.test(str);// boolean b2 = p2.test(str);// if (b1 && b2) {// System.out.println("即包含W,也包含H");// }// 使用Lambda表达式判断一个字符串中即包含W,也包含HString str = "Hello World";boolean b = p1.and(p2).test(str);if (b) {System.out.println("即包含W,也包含H");}// 使用Lambda表达式判断一个字符串中包含W或者包含Hboolean b1 = p1.or(p2).test(str);if (b1) {System.out.println("包含W或者包含H");}}}
默认方法:negate
使用Lambda表达式判断一个字符串中即不包含W
“与”、“或”已经了解了,剩下的“非”(取反)也会简单。默认方法 negate 的JDK源代码为:

从实现中很容易看出,它是执行了test方法之后,对结果boolean值进行“!”取反而已。一定要在 test 方法调用之前调
用 negate 方法,正如 and 和 or 方法一样:
package com.itheima.demo03functionalinterface;import java.util.function.Predicate;public class Demo08Predicate_And_Or_Negate {// 使用Lambda表达式判断一个字符串中即包含W,也包含H// 使用Lambda表达式判断一个字符串中包含W或者包含H// 使用Lambda表达式判断一个字符串中不包含Wpublic static void main(String[] args) {test((String str) -> {// 判断是否包含Wreturn str.contains("W");}, (String str) -> {// 判断是否包含Hreturn str.contains("H");});}public static void test(Predicate<String> p1, Predicate<String> p2) {// String str = "Hello orld";// boolean b1 = p1.test(str);// boolean b2 = p2.test(str);// if (b1 && b2) {// System.out.println("即包含W,也包含H");// }// 使用Lambda表达式判断一个字符串中即包含W,也包含HString str = "Hello World";boolean b = p1.and(p2).test(str);if (b) {System.out.println("即包含W,也包含H");}// 使用Lambda表达式判断一个字符串中包含W或者包含Hboolean b1 = p1.or(p2).test(str);if (b1) {System.out.println("包含W或者包含H");}// 使用Lambda表达式判断一个字符串中不包含Wboolean b2 = p1.negate().test("Hello W");// negate相当于取反 !booleanif (b2) {System.out.println("不包含W");}}}
1.8 小结
- Supplier接口

- Consumer接口

3. Function接口

4. Predicate接口



