Java系列之:函数式接口

  • 一、函数式接口
  • 二、函数式接口作为方法的返回值
  • 三、Supplier接口
  • 四、Supplier接口获取数组最大值
  • 五、Consumer接口
  • 六、Consumer接口案例
  • 七、Predicate接口
  • 八、Predicate接口案例
  • 九、Function接口
  • 十、Function接口案例


一、函数式接口

函数式接口:

  • 有且仅有一个抽象方法的接口
  • Java中的函数式编程体现就是Lambda表达式,所以函数式接口可以适用于Lambda使用的接口
  • 只有确保接口中有且仅有一个抽象方法,Java中的Lambda才能顺利进行推导

定义函数式接口:

  • @FunctionalInterface
  • 放在接口定义的上方:如果接口是函数式接口,编译通过,如果不是,编译失败

注意:

  • 定义函数式接口,@FunctionalInterface接口是可选的,不写这个注释,只要保证满足函数式接口定义的条件,也照样是函数式接口,建议加上该注解。

函数式接口作为方法的参数:

  • 方法的参数是一个函数式接口,可以使用Lambda表达式作为参数传递
public interface SubString {
    String mySubString(String s,int x,int y);
}
public class ConvertDemo {
    public static void main(String[] args) {

        useConverter((String s,int x,int y) -> {
            return s.substring(x,y);
        });

        useConverter((s,x,y) -> s.substring(x,y));

        //引用类的实例方法
        useConverter(String::substring);

    }


    public static void useConverter(SubString c){
        String s = c.mySubString("HelloWorld", 2, 5);
        System.out.println(s);
    }
}

二、函数式接口作为方法的返回值

  • 定义一个类,提供两个方法
  • 一个方法是Comparator getComparator()方法返回值Comparator是一个函数式接口
  • 一个方法是主方法,在主方法中调用getComparator方法
import java.util.ArrayList;
import java.util.Collections;
import java.util.Comparator;

public class ComparatorDemo {
    public static void main(String[] args) {

        ArrayList<String> strings = new ArrayList<>();
        strings.add("cccc");
        strings.add("bb");
        strings.add("ffffff");
        strings.add("ggg");
        strings.add("h");

        System.out.println("排序前:" + strings);

        Collections.sort(strings,getComparator());

        System.out.println("排序后:" + strings);

    }


    private static Comparator<String> getComparator(){
        //匿名内部类实现方式
//        Comparator<String> comp = new Comparator<String>() {
//            @Override
//            public int compare(String s1, String s2) {
//                return s1.length() - s2.length();
//            }
//        };
//        return comp;

//        return new Comparator<String>() {
//            @Override
//            public int compare(String s1, String s2) {
//                return s1.length() - s2.length();
//            }
//        };


        //Lambda表达式
//        return (String s1,String s2) -> {
//            return s1.length() - s2.length();
//        };

        return (s1,s2) -> s1.length() - s2.length();

    }
}
  • 方法的返回值是一个函数式接口,使用Lambda表达式作为结果返回
private static Comparator<String> getComparator(){ 
     return (s1,s2) -> s1.length() - s2.length();
     }

三、Supplier接口

Supplier:包含一个无参的方法

  • T get():获得结果
  • 该方法不需要参数,会按照某种实现逻辑(由Lambda表达式实现)返回一个数据
  • Supplier<T>接口也被称为生产型接口,如果指定了接口的泛型是什么类型,接口中的get方法就会产生什么类型的数据
import java.util.function.Supplier;

public class SupplierDemo {
    public static void main(String[] args) {
//        String s = getString(() -> {
//            return "火影";
//        });

        String s = getString(() -> "火影");

        System.out.println(s);


        Integer i = getInteger(() -> 20);
        System.out.println(i);
    }

    //定义一个方法,返回一个字符串数据
    private static String getString(Supplier<String> sup){

        return sup.get();

    }

    //定义一个方法,返回一个整数数据
    private static Integer getInteger(Supplier<Integer> sup){
        return sup.get();
    }
}

输出如下所示:
火影
20

四、Supplier接口获取数组最大值

import java.util.function.Supplier;

public class SupplierGetMax {
    public static void main(String[] args) {

        int[] arr = {19,32,52,31,25};

        int maxvalue = getMax(() ->{
            int max = arr[0];
            for(int i=1;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();
    }
}

五、Consumer接口

Consumer<T>:包含两个方法

  • void accept(T t):包含两个方法
  • default Consumer<T> andThen(Consumer after):返回一个组合的Consumer,依次执行此操作,然后执行after操作
  • Consumer<T>接口也被称为消费型接口,消费的数据的数据类型由泛型指定
import java.util.function.Consumer;

public class ConsumerDemo {
    public static void main(String[] args) {
        operatorString1("火影",s -> {
            System.out.println(new StringBuilder(s).reverse().toString());
        });

        operatorString2("火影",s -> System.out.println(s),
                s -> System.out.println(new StringBuilder(s).reverse().toString()));


    }

    private static void operatorString2(String name,Consumer<String> con1,Consumer<String> con2){
        con1.andThen(con2).accept(name);
    }

    //定义一个方法,消费一个字符串数据
    private static void operatorString1(String name, Consumer<String> con){
        con.accept(name);
    }
}

六、Consumer接口案例

import java.util.function.Consumer;

public class ConsumerDemo {
    public static void main(String[] args) {

        String[] strArray = {"火影,10","海贼王,23"};

        printInfo(strArray,(String str) ->{
            String name = str.split(",")[0];
            System.out.print("动画名称:" + name);
        },(String str) -> {
            int year = Integer.parseInt(str.split(",")[1]);
            System.out.println(",更新时长:" +year);
        });

    }

    private static void printInfo(String[] strArray,Consumer<String> con1,Consumer<String> con2){
        for(String str: strArray){
            con1.andThen(con2).accept(str);
        }
    }
}

输出如下所示:
动画名称:火影,更新时长:10
动画名称:海贼王,更新时长:23

七、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>接口通常用于判断参数是否满足指定的条件
import java.util.function.Predicate;

public class PredictDemo {
    public static void main(String[] args) {

        boolean b = checkString("hello", s -> s.length() > 8);
        System.out.println(b);

        boolean b1 = checkString2("hello123456", s -> s.length() > 8, s -> s.length() < 10);
        System.out.println(b1);


    }


    //判断给定的字符串是否满足要求
    private static boolean checkString(String s, Predicate<String> pre){
//        return pre.test(s);
        return pre.negate().test(s);

    }

    //同一个字符串给出两个不同的判断条件,最后把这两个判断的结果做逻辑与运算的结果作为最终的结果
    private static boolean checkString2(String s,Predicate<String> pre1,Predicate<String> pre2){
//        return pre1.and(pre2).test(s);
        return pre1.or(pre2).test(s);
    }
}

八、Predicate接口案例

  • String[] strArray = {"海贼王,23“,“火影,12”,“犬夜叉,2”,“棒球英豪,6”}
  • 字符数组有多条动漫信息,通过Predicate接口的拼装将符合要求的字符串筛选到集合ArrayList中,并遍历ArrayList集合
  • 满足要求:动漫名称大于2,更新时长小于15年大于2年的
import java.util.ArrayList;
import java.util.function.Predicate;

public class PredictDemo {
    public static void main(String[] args) {

        boolean b = checkString("hello", s -> s.length() > 8);
        System.out.println(b);

        boolean b1 = checkString2("hello123456", s -> s.length() > 8, s -> s.length() < 10);
        System.out.println(b1);


        String[] strArray = {"海贼王,23","火影,12","犬夜叉,4","棒球英豪,6"};
        ArrayList<String> filter = filter(strArray, s -> s.split(",")[0].length() > 2,
                s -> Integer.parseInt(s.split(",")[1]) > 2 && Integer.parseInt(s.split(",")[1]) < 15);

        for(String s:filter){
            System.out.println(s);
        }


    }


    //判断给定的字符串是否满足要求
    private static boolean checkString(String s, Predicate<String> pre){
//        return pre.test(s);
        return pre.negate().test(s);

    }

    //同一个字符串给出两个不同的判断条件,最后把这两个判断的结果做逻辑与运算的结果作为最终的结果
    private static boolean checkString2(String s,Predicate<String> pre1,Predicate<String> pre2){
//        return pre1.and(pre2).test(s);
        return pre1.or(pre2).test(s);
    }

    private static ArrayList<String> filter(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;
    }
}

输出如下所示:
犬夜叉,4
棒球英豪,6

九、Function接口

Function<T,R>:常用的两个方法

  • R apply(T t):将此函数应用于给定的参数
  • default <V> Function andThen(Function after):返回一个组合函数,首先将函数应用于输入,然后将after函数应用于结果
  • Function<T,R>接口通常用于对参数进行处理,转换(处理逻辑由Lambda表达式实现),然后返回一个新的值
import java.util.function.Function;

public class FunctionDemo {
    public static void main(String[] args) {

        convert1("100",s -> Integer.parseInt(s));

        convert2(100,i -> String.valueOf(i + 280));

        convert3("100", s -> Integer.parseInt(s),i -> String.valueOf(i + 188));

    }


    //定义一个方法,把一个字符串转换int类型,在控制台输出
    private static void convert1(String s, Function<String,Integer> fun){
        Integer i = fun.apply(s);
        System.out.println(i);
    }

    //定义一个方法,把一个int类型宕数据加上一个整数之后,转为字符串在控制台输出
    private static void convert2(Integer i,Function<Integer,String> fun){
        String s = fun.apply(i);
        System.out.println(s);
    }

    //定义一个方法,把一个字符串转换int类型,把int类型的数据加上一个整数之后,转为字符串在控制台输出
    private static void convert3(String s,Function<String,Integer> fun1,
                                Function<Integer,String> fun2){
        String ss = fun1.andThen(fun2).apply(s);
        System.out.println(ss);
    }
}

输出如下所示:
100
380
288

十、Function接口案例

  • String s = “海贼王,23”
  • 请按照指定的要求进行操作:



  • 通过Function接口来实现函数拼接
import java.util.function.Function;

public class FunctionDemo {
    public static void main(String[] args) {

        String s = "海贼王,23";

//        convert(s,(String ss) -> {return s.split(",")[1];},
//                (String ss) -> {return Integer.parseInt(ss);},(Integer i) -> {return i + 10;});

//        convert(s,ss -> ss.split(",")[1],ss -> Integer.parseInt(ss),i -> i +10);

        convert(s,ss -> ss.split(",")[1],Integer::parseInt,i -> i +10);

    }


    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);
        System.out.println(i);
    }
}