什么是函数式接口和常用的函数式接口
1. 什么是函数式接口
接口中有且只有一个 抽象方法的接口被称作函数式接口
Java 中函数式编程体现就是 Lambda 表达式,所以对于 Lambda 表达式来说函数式接口尤为重要
如何检测一个接口是不是函数式接口?
@FunctionalInterface 注解,在定义接口的上方加上注解,编译可以通过就是函数式接口,否则不是
【注意】
在自己写接口时,如果接口中只含有一个 abstract 方法那么这样的接口无论加不加 @FunctionalInterface 注解都是函数式接口,科学建议这样的接口一定要加上@FunctionalInterface 注解
2. 常用的函数式接口
2.1 Consumer 接口 ( 消费者接口 )
Consumer 接口又被称作消费者接口
接口中有一个 void accept( T t ); 方法,方法需要一个泛型参数,但是没有返回值
Consumer 接口源码:
@FunctionalInterface
public interface Consumer<T> {
void accept(T t);
}
代码演示:
定义了一个测试方法 testConsumerLambda () 需要参数为:a. 一个 String 类型字符串 b. Consumer 接口,接口直接约束参数泛型为 String 类型,方法体为接口的实现类对象调用 accept () 方法。
main 方法中 a. 使用 Lambda 表达是重写了 accept () 方法
b. 方法引用,引用 System 中的 out ( ) 方法 作为 accept () 的重写方法,为什么可以引用? 前提必须要求 引用的方法的参数列表和返回值必须和函数式接口中 abstract 修饰的方法的 参数列表和返回值相同。
package com.zixue.demo;
import java.util.function.Consumer;
/**
* @author: 85409 2023/3/7 20:42
* @description: TODO
*/
public class ConsumerDemo {
public static void main(String[] args) {
// Lambda 表达式
testConsumerLambda("Lambda表达式", s -> System.out.println(s));
// 方法引用
testConsumerLambda("Lambda表达式", System.out::println);
}
public static void testConsumerLambda(String s, Consumer<String> con) {
con.accept(s);
}
}
2.2 Supplier 接口 ( 生产者接口 )
Supplier 接口又称作生产者接口
接口中有一个 R get(); 方法,方法不需要参数,但是有一个返回值
Supplier 接口源码:
@FunctionalInterface
public interface Supplier<T> {
T get();
}
代码演示:
package com.zixue.demo;
import java.util.function.Supplier;
/**
* @author: 85409 2023/3/7 20:51
* @description: TODO
*/
public class SupplierDemo {
public static void main(String[] args) {
// Lambda 表达式
testLambda(() -> "我是 Supplier 返回的字符串");
}
public static void testLambda(Supplier<String> sup) {
String s = sup.get();
System.out.println(s);
}
}
2.3 Predicate 接口 ( 过滤,判断接口 )
Predicate 接口又称作过滤,判断型接口
接口中有一个 boolean test( T t ) 方法,需要一个泛型参数,返回值为 boolean 类型
Predicate 接口 源码:
public interface Predicate<T> {
boolean test(T t);
}
代码演示
public class PredicateDemo {
public static void main(String[] args) {
// Lambda 表达式
String str = "我肯定大于5吧";
testLambda(str, s -> str.length() > 5);
}
public static void testLambda(String s, Predicate<String> pre) {
boolean test = pre.test(s);
if (test) {
System.out.println("字符串长度大于5");
}else {
System.out.println("字符串长度不大于5");
}
}
}
stream 流中 filter 方法的参数也为 Predicate 接口,可以使用 Lambda 方式实现方法。
Predicate 接口中 boolean test(T t) 返回值为 boolean 类型,filter 会自动过滤到 false 结果,来实现集合中元素的过滤。
package com.zixue.demo;
import java.util.ArrayList;
/**
* @author: 85409 2023/3/7 21:34
* @description: TODO
*/
public class PredicateStreamDemo {
public static void main(String[] args) {
// stream 流
ArrayList<String> list = new ArrayList<>();
list.add("汤米·谢尔比");
list.add("亚瑟·谢尔比");
list.add("约翰·谢尔比");
list.add("所罗门");
list.add("Ada Shelby");
list.add("Grace Burgess");
list.add("Alfie Solomons");
// filter 参数为 Predicate 接口 进而调用 boolean test(T t) 方法,来实现过滤的目的
list.stream()
.filter(s -> s.length() > 6)
.forEach(System.out::println);
}
}
2.4 Comparator 接口( 比较器接口 )
Comparator 接口又称作比较器接口
接口中有一个 int compare( T o1, T o2 ); 方法,方法需要两个参数,有一个 int 类型返回值
@FunctionalInterface
public interface Comparator<T> {
int compare(T o1, T o2);
}
代码演示:
代码以 Person 类型数组作为例子 Person 类中 成员属性为 int 类型 id ,String 类型 name,int 类型 age
定义方法 testLambda() 方法 需要传入参数 Person 类型数组 和 Compartor 比较器接口,方法体中使用 Arrays 工具类中的 sort() 方法 需要参数为: 需要排序的数组,排序的方式
需要排序的数组:Person 类型数组
排序的方式: 我们传入 Compartor 接口自定义排序方式。代码中重写的 compare 方法是,通过 Person 中 age 属性进行排序
/*
Person 类
*/
class Person {
private int id;
private String name;
private int age;
...... // 省略了 getter and setter 方法 和 构造方法 toString 方法
}
public class CompartorDemo {
public static void main(String[] args) {
Person[] arr = new Person[10];
for (int i = 0; i < 10; i++) {
arr[i] = new Person(i + 1, "张三", (int) (Math.random() * 100));
}
// Lambda 表达式
testLambda(arr, (p1, p2) -> p1.getAge() - p2.getAge());
// stream 流 + 方法引用
Arrays.stream(arr).forEach(System.out::println);
}
public static void testLambda(Person[] arr, Comparator<Person> com) {
// 使用了 Arrays 工具类的 sort() 排序方法
Arrays.sort(arr, com);
}
}
2.5 Function<T,R> 接口 (类型转换接口)
Function 接口又被称为转换接口
接口中有一个 R apply ( T t ); 泛型 T 通过传入参数时约束具体数据类型, 返回值类型是自定义方法时程序员想要的被返回的数据类型。
@FunctionalInterface
public interface Function<T> {
R apply(T t);
}
代码演示:
定义了一个测试方法,方法需要传入两个参数
a. char 类型数组,用于数据类型转换的参数,目的将 char 类型数组转换为 String 类型
b. Function 接口,使用接口中 唯一 abstract 方法 apply ( ) 达到转换类型的目的
最后在 main 方法中将 chars 数组作为参数传入 testLambda 方法中,使用 Lambda 表达式对 apply ( ) 方法进行重写。
package com.zixue.demo;
import java.util.function.Function;
/**
* @author: 85409 2023/3/7 22:53
* @description: TODO
*/
public class FunctionDemo {
public static void main(String[] args) {
char[] chars = {'L', 'a', 'm', 'b', 'd', 'a', '表', '达', '式', '演', '示', 'F', 'u', 'c', 't', 'i', 'o', 'n', '接', '口'};
testLambda(chars, (s) -> new String(chars));
}
/**
* 测试方法使用 Lambda 表达式实现函数式接口
*
* @param chars 传入的 char[] 类型数组
* @param fun 参数为 Function 接口
*/
public static void testLambda(char[] chars, Function<char[], String> fun) {
System.out.println(fun.apply(chars));
}
}