JAVA 函数式接口
1. 函数式接口
1.1 函数式接口概述
函数式接口:有且仅有一个抽象方法的接口
Java 中的函数式编程体现的就是 Lambda 表达式,所有函数式较快就是可以适用于 Lambda 使用的接口
只有确保接口中有且只有一个抽象方法,Java中的Lambda才能顺利地进行推导
如何检测一个接口是不是函数式接口呢?
@Functionallnterface
- 放在接口定义的上方:如果接口时函数时接口,编译通过;如果不是,编译失败
注意
- 我们自己定义函数式接口的时候,
@Functionallnterface
是可选的,就算我不写这个注释,只有保证满足函数式接口定义的条件,也照样是函数式接口。但是,建议加上 该注释
1.2 函数式接口作为方法的参数
需求:
- 定义一个类(RunnableDemo),在类中提供两个方法
- 一个方法是:
startThread(Runnable r)
方法参数Runnable
是一个函数式接口 - 一个方法是主方法,在主方法中调用
startThread
方法
- 一个方法是:
如果方法的参数是一个函数式接口,我们可以使用 Lambda 表达式作为参数传递
startThread(() -> System.out.println(Thread.currentThread().getName() + "线程启动了"));
1.3 函数式接口作为方法的返回值
需求:
-
定义一个类(CompaatorDemo),在类中提供两个方法
- 一个方法是:
Comparator<String>getComparator()
方法返回值 Comparator 是一个函数式接口 - 一个是主方法,在主方法中调用
getComparator
方法
如果方法的返回值是一个函数式接口,我们可以使用 Lambda 表达式作为结果返回
- 一个方法是:
-
private static Comparator<String> getComparator(){ return(s1, s2) -> s1.length() - s2.length(); }
1.4 常用的函数式接口
Java 8在 Java.util.function
包下预定义了大量的函数式接口供我们使用
现在重点学习下面4个接口:
Supplier
接口Consumer
接口Predicate
接口Function
接口
1.5 Supplier 接口
Supplier<T>
:包含一个无参的方法
T get()
:获得结果- 该方法不需要参数,他会安装某种实现逻辑(有Lambda表达式实现)返回一个数据
Supplier<T>
:接口也称为生产型接口,如果我们指定了接口的泛型是什么类型,那么接口中的get方法就会产生什么类型的数据供我们使用
练习
- 定义一个类(
SupplierTest
),在类中提供两个方法- 一个方法是:
int getMax(Supplier<Integer> sup)
:用于返回一个int数组中的最大值 - 一个方法是主方法,在主方法中调用
getMax
方法
- 一个方法是:
import java.util.function.Supplier;
public class SupplierTest {
public static void main(String[] args) {
//定义一个int数组
int[] arr = {19, 50, 28, 36, 44};
//在主方法中调用 getMax方法
int maxValue = getMax(() -> {
int max = arr[0];
for (int i = 0; i < arr.length; i++) {
if (arr[i] > max) {
max = arr[i];
}
}
return max;
});
//输出结果
System.out.println(maxValue);
}
private static int getMax(Supplier<Integer> sup) {
return sup.get();
}
}
1.6 Consumer 接口
Consumer<T>
:包含两个方法
void accept(T t)
:对给定的参数执行此操作default Consumer<T> andThen(Consumer after)
:返回一个组合的Consumer
,依次执行此操作,然后执行after
操作Consumer< T>
接口也被称为消费性接口,它消费的数据的数据类型有泛型执行
练习
String[] strArray = {"大雄, 18", "静香, 19", "胖虎, 20"};
- 字符串数组中有多条信息,请按照格式:“ 姓名:XX,年龄:XX ” 的格式将信息打印出来
- 要求:
- 把打印姓名的动作作为第一个
Consumer
接口的Lambda
实例 - 把打印年龄的动作作为第二个
Consumer
接口的Lambda
实例 - 将两个
Consumer
接口按照顺序组合到一起使用
- 把打印姓名的动作作为第一个
import java.util.function.Consumer;
public class ConsumerTest {
public static void main(String[] args) {
String[] strArray = {"大雄,18", "静香,19", "胖虎,20"};
// printInfo(strArray, (String str) -> {
// String name = str.split(",")[0];
// System.out.print("姓名:" + name);
// }, (String str) -> {
// int age = Integer.parseInt(str.split(",")[1]);
// System.out.println(",年龄:" + age);
// });
printInfo(strArray, str -> System.out.print("姓名:" + str.split(",")[0]),
str -> System.out.println(",年龄:" + Integer.parseInt(str.split(",")[1])));
}
private static void printInfo(String[] strArray, Consumer<String> con1, Consumer<String> con2) {
for (String str : strArray) {
con1.andThen(con2).accept(str);
}
}
}
1.7 Predicate接口
Predicate<T>
:常用的四个方法
boolean test(T t)
:对给定的参数进行判断(判断逻辑有Lambda表达式实现),返回一个布尔值default Predicate<T> negate()
:返回一个逻辑的否定,对应逻辑非default Predicate<T> and(Predicate other)
:返回一个组合判断,对应短路与default Predicate<T> or(Predicate other)
:返回一个组合判断,对应短路或Predicate<T>
接口通常用于判断参数是否满足指定的条件
练习
Stri ng[] strArray = {"林青霞,30", "柳岩,34", "张曼玉,35", "貂蝉,31", "王祖贤,33"};
- 字符串数组中有多条信息,请通过
Predicate
接口的拼装将符合要求的字符串筛选到集合ArrayList中,并遍历ArrayList集合 - 同时满足如下要求:姓名长度大于2;年龄大于19
- 分析:
- 有两个判断条件,所以需要使用两个Predicate接口,对条件进行判断
- 必须同时满足两个条件,所以可以使用and分别连接两个判断条件
import java.util.ArrayList;
import java.util.function.Predicate;
public class PredicateTest {
public static void main(String[] args) {
String[] strArray = {"林青霞,30", "柳岩,34", "张曼玉,35", "貂蝉,31", "王祖贤,33"};
ArrayList<String> array = myFilter(strArray, s -> s.split(",")[0].length() > 2,
s -> Integer.parseInt(s.split(",")[1]) > 33);
for (String str : array) {
System.out.println(str);
}
}
//通过Predicate接口的拼装将符合要求的字符串筛选到集合ArrayList中
private static ArrayList<String> myFilter(String[] strArray, Predicate<String> pre1, Predicate<String> pre2) {
//定义一个集合
ArrayList<String> array = new ArrayList<String>();
//遍历数组
for (String str : strArray) {
if (pre1.and(pre2).test(str)) {
array.add(str);
}
}
return array;
}
}
1.8 Function 接口
Function<T, R>
:常用的两个方法
R apply(T t)
:将此函数应用于给定的参数default<V> Function andThen(Function after)
:返回一个组合函数,首先将该函数应用于输入,然后将after
函数应用于结果Function<T, R>
接口通常用于对参数进行处理,转换(处理逻辑由Lambda表达式实现),然后返回一个新的值
练习
String s = "大雄,18";
- 请按照指定要求进行操作
- 将字符串截取得到数字年龄部分
- 将上一步的年龄字符串转成为int类型的数据
- 将上一步的int数据加70,得到一个int结果,在控制台输出
- 通过Function皆空来实现函数拼接
import java.util.function.Function;
public class FunctionTest {
public static void main(String[] args) {
String s = "大雄,18";
// convert(s, (String ss) -> {
// return s.split(",")[1];
// }, (String ss) -> {
// return Integer.parseInt(ss);
// }, (Integer i) -> {
// return i + 70;
// });
// convert(s, ss -> ss.split(",")[1], ss -> Integer.parseInt(ss), i -> i + 70);
convert(s, ss -> ss.split(",")[1], Integer::parseInt, i -> i + 70);
}
private static void convert(String s, Function<String, String> fun1, Function<String, Integer> fun2, Function<Integer, Integer> fun3) {
// Integer i = fun1.andThen(fun2).andThen(fun3).apply(s);
int i = fun1.andThen(fun2).andThen(fun3).apply(s);
System.out.println(i);
}
}