前置知识
- Lambda表达式
- Lombok(非必须)
- 泛型
什么是函数式接口
接口、抽象类、普通类都能定义变量。
String定义的变量能存String类型的值
既然是函数式接口定义的变量,那么就能存函数(函数=方法,叫法不同,Java多称为方法,其他语言多称为函数)
一般来说,引用类型只能存对象,而函数式接口定义的变量可以存一个函数
//用接口定义变量
List<Student> list;
//用String定义一个变量
String str;
//用函数式接口定义一个变量
Supplier<Student> supplier;
一、以Supplier举例(提供者)
首先它是一个接口,所以能定义一个变量
package java.util.function;
@FunctionalInterface
public interface Supplier<T> {
T get();
}
从源码上看,此函数式接口定义的变量所存的函数要返回 T 泛型的对象,不接收参数
解释:此处主要看第 5 行 T get() ,因为这是一个接口,接口的抽象方法必须被实现,而这里是一个函数式接口,所存的变量(即函数)要满足这个抽象方法的格式。(若难以理解可将Supplier看完再看此解释)
一个数据类
@Data
public class Student {
private int number;
private String name;
}
//这就是将一个构造函数放到了supplier变量中
//等号右边使用Lambda表达式,相当于一个匿名函数
Supplier<Student> supplier = () -> new Student(1, "Tom");
根据源码可知,这个变量,supplier只有一个方法get方法,得到一个T泛型的对象
所以每次调用这个get方法相当于调用了new Student(1, “Tom”)这个构造方法
Supplier<Student> supplier = () -> new Student(1, "Tom");
//每次调用会得到一个不同于之前的Student对象
Student student = supplier.get();
而这个Supplier是一个提供者,必须返回一个对象
所以,不一定要用构造函数,只要这个变量存储的函数能返回一个符合泛型的对象即可
public static Student getStudent(){
Student stu = new Student(2,"Jerry");
return stu;
}
public static void main(String[] args) {
Supplier<Student> supplier = () -> new Student(1, "Tom");
Student student = supplier.get();
Supplier<Student> supplier2 = Test::getStudent;//这样也是可以的,调用上面的static函数
}
但是存储的函数必须是有明确返回类型的,如上
下面这样不行
二、以Consumer为例(消费者)
从源码来看,此函数式接口定义的变量所存的函数必须接收一个 T 泛型参数,不返回(即看 5 行,void accept(T t) )
package java.util.function;
@FunctionalInterface
public interface Consumer<T> {
void accept(T t);
}
右边这个Lambda表达式可视作一个匿名函数,符合void accept(T t)格式;
Consumer<Student> consumer = (Student stu) -> System.out.println(stu.toString());
使用如下
consumer.accept(getStudent());
consumer.accept(new Student(1, "Tom"));
consumer.accept(supplier.get());
即调用accept等于调用右边Lambda表达式定义的匿名方法