一,函数式接口的由来
在Java中,通常一个函数代表一个行为,比如实现一个简单的加减乘除计算器,通常我们需要去定义4个函数,当这个计算器需要扩展平方,开方等功能的时候,则还需要再去定义新的函数来实现。
然而我们发现,每个函数的实现仅仅是一个计算行为,如果函数中能够传递行为,那么只需要定义一个函数就能实现了,函数式接口正是基于这种来设计的。
二,函数式接口的定义
函数式接口(Function Interface):有且只有一个抽象方法的接口我们称为函数式接口。
注意:函数式接口不一定需要@FunctionalInterface来标识,也可以定义default,static修饰的方法。
引申:接口中为什么需要定义default函数?
比如ArrayList,LinkList是List接口的实现,当List中需要定义新的函数时候,所有实现List类都需要重写,为了迭代的减少影响,Java的设计者就定义一个default来修饰新增的方法。
三,函数式接口的实现方式
函数式接口有3种实现,Lambda表达式,方法引用,构造方法引用
Lambda表达式:() -> {}
方法引用:String::toUpperCase
构造方法引用:ArrayList::new
Lambda表达式
基本语法:
(args ...) -> {body}
(type1 args1,type2 args2) -> {body}
示例:
(int a,int b) -> {return a+b;}
() -> System.out.println("hello world")
描述:
1,一个Lambda表达式可以有零个或者多个参数
2,参数的类型既可以明确声明,也可以根据上下文来推断。例如(int a)与(a)效果相同
3,所有参数包含在圆括号内,参数之间用逗号相隔,例如:(a,b)或者(int a,int b)
4,空圆括号代表参数为空。例如() -> 42
5, 当只有一个参数,且其类型可以推到时,圆括号()可以省略,例如:a->return a*a
6, 如果Lambda表达式的body只有一条语句的时候,{}可以省略
7, 如果lambda表达式的body有多条语句的时候,必须用{}
四,典型的函数式接口
函数式接口都在java.util.function包下
1,Function接口
特点:输入一个参数,返回一个参数
@FunctionalInterface
public interface Function<T, R> {
//输入T,返回R
R apply(T t);
}
场景一:类型转换
public class FunctionDemo {
public static void main(String[] args) {
//Lambda表达式实现
//value -> String.valueOf(value)) 转换行为
System.out.println(computer(2, value -> String.valueOf(value)));
}
public static int computer(Integer args0, Function<Integer,String> fn){
return fn.apply(args0);
}
}
Function接口的compose和andThen组合方法
public static void main(String[] args) {
System.out.println(compute1(2, val -> val * 3, val -> val * val));
System.out.println(compute2(2, val -> val * 3, val -> val * val));
}
//计算顺序:先执行fn2,然后把fn2的结果给fn1执行
public static int compute1(int a, Function<Integer,Integer> fn1, Function<Integer,Integer> fn2){
return fn1.compose(fn2).apply(a); //12
}
//计算顺序:先执行fn1,然后把执行结果给fn2
public static int compute2(int a, Function<Integer,Integer> fn1, Function<Integer,Integer> fn2){
return fn1.andThen(fn2).apply(a); //36
}
}
2,BiFunction接口
特点:输入两个参数,返回一个参数
@FunctionalInterface
public interface BiFunction<T, U, R> {
//传递T,U两个参数,返回R
R apply(T t, U u);
}
场景一:实现一个加减乘除计算器
//抽象出计算函数
public static int compute(int a, int b, BiFunction<Integer,Integer,Integer> biFunction){
return biFunction.apply(a, b);
}
//传递计算行为
System.out.println(compute3(2, 3, (a1, a2) -> a1 + a2));//加法
System.out.println(compute3(2, 3, (a1, a2) -> a1 - a2));//减法
System.out.println(compute3(2, 3, (a1, a2) -> a1 * a2));//乘法
System.out.println(compute3(2, 3, (a1, a2) -> a1 / a2));//除法
场景二:从集合中找出年龄大于60岁的员工
public static List<Person> getPersonByAge(int age,List<Person> mataList){
BiFunction<Integer,List<Person>,List<Person>> biFunction = (ageOfPerson,personList) ->{
return personList.stream().filter(person -> person.getAge()>ageOfPerson).collect(Collectors.toList());
};
return biFunction.apply(age, mataList);
}
getPersonByAge(60, list).forEach(person -> System.out.println(person.getUsername()));
3,Predicate 断定行接口
特点:输入一个参数,返回一个Boolean值
@FunctionalInterface
public interface Predicate<T> {
//输入一个值,返回一个Boolean值
boolean test(T t);
}
场景一:找出集合中的小于5的数字
public static void main(String[] args) {
List<Integer> list = Arrays.asList(1, 2, 3, 4, 5, 6, 7, 8, 9);
//找出小于5的数字
conditionFilter(list, (it) -> it<5);
}
public static void conditionFilter(List<Integer> list, Predicate<Integer> predicate) {
list.forEach(integer -> {
if (predicate.test(integer)) {
System.out.println(integer);
}
});
}
Predicate接口中的and方法
场景一:找出集合中大于4,且为偶数的数字
public static void main(String[] args) {
List<Integer> list = Arrays.asList(1, 2, 3, 4, 5, 6, 7, 8, 9);
conditionFilter2(list, value -> value > 4, va -> va%2 == 0);
}
//给定参数age,到集合中查找list,既要满足predicate1,也要满足predicate2
public static void conditionFilter2(List<Integer> list,
Predicate<Integer> predicate1,
Predicate<Integer> predicate2) {
for(Integer integer: list){
if(predicate1.and(predicate2).test(integer)){
System.out.println(integer);
}
}
}
Predicate接口中的negate(取反)方法
public static void conditionFilterNegate(List<Integer> list,
Predicate<Integer> predicate1,
Predicate<Integer> predicate2) {
for(Integer integer: list){
if(predicate1.and(predicate2).negate().test(integer)){
System.out.println(integer);
}
}
}
4,Supplier供给型接口
特点:无输入,有输出
@FunctionalInterface
public interface Supplier<T> {
//没有输入参数,返回T
T get();
}
5,Consumer 消费型接口
特点:有输入,无输出
@FunctionalInterface
public interface Consumer<T> {
//输入参数T,无返回
void accept(T t);
}