Java8函数式接口

792 阅读4分钟

一,函数式接口的由来

在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);
}