美文网首页
[java]18、函数式接口

[java]18、函数式接口

作者: 史记_d5da | 来源:发表于2021-10-21 23:14 被阅读0次

    1、概述

    有且只有一个抽象方法的接口,称之为函数式接口、当然接口中可以包含其他的方法(默认,静态,私有)
    使用@FunctionalInterface注解
    以下是函数式接口的使用

    // MyFunctionalInterface.java
    @FunctionalInterface
    public interface MyFunctionalInterface {
        //定义一个抽象方法
        public abstract void method();
    }
    
    // MyFunctionalInterfaceImpl.java
    public class MyFunctionalInterfaceImpl implements MyFunctionalInterface{
        @Override
        public void method() {
        }
    }
    
    // Demo.java
    public class Demo {
        //定义一个方法,参数使用函数式接口MyFunctionalInterface
        public static void show(MyFunctionalInterface myInter){
            myInter.method();
        }
        public static void main(String[] args) {
            //调用show方法,方法的参数是一个接口,所以可以传递接口的实现类对象
            show(new MyFunctionalInterfaceImpl());
    
            //调用show方法,方法的参数是一个接口,所以我们可以传递接口的匿名内部类
            show(new MyFunctionalInterface() {
                @Override
                public void method() {
                    System.out.println("使用匿名内部类重写接口中的抽象方法");
                }
            });
    
            //调用show方法,方法的参数是一个函数式接口,所以我们可以Lambda表达式
            show(()->{
                System.out.println("使用Lambda表达式重写接口中的抽象方法");
            });
    
            //简化Lambda表达式
            show(()-> System.out.println("使用Lambda表达式重写接口中的抽象方法"));
        }
    }
    

    2、函数式接口作为返回值类型

    public static Comparator<String> getComparator() {
            // 返回匿名函数
            /* return new Comparator<String>() {
                @Override
                public int compare(String o1, String o2) {
                    return o2.length() - o1.length();
                }
            }; */
            // 返回一个lambda表达式
            /* return (String o1, String o2)-> {
              return o2.length() - o1.length();
            };*/
            return (o1, o2) -> o2.length() - o1.length();
    }
    

    3、函数式接口作为参数

    public class Demo01Runnable {
        public static void startThread(Runnable run) {
            new Thread(run).start(); // 开启多线程
        }
        public static void main(String[] args) {
            // 匿名函数
            startThread(new Runnable() {
                @Override
                public void run() {
                    System.out.println(Thread.currentThread().getName() + "线程启动了");
                }
            });
            // lambda表达式
            startThread(()->System.out.println(Thread.currentThread().getName() + "线程启动了"));
        }
    }
    

    4、Supplier接口

    java.util.function.Supplier<T>接口仅包含一个参数的方法:T get(),用来获取一个泛型参数指定类型的对象数据
    Supplier<T>接口被称之为生产型接口

    public class Demo01Supplier {
        // 定义一个方法,方法的参数传递Supplier<T>接口,泛型执行String,get方法就会返回一个String
        public static String getString(Supplier<String> sup) {
            return sup.get();
        }
        public static void main(String[] args) {
            // 调用getString方法,方法的参数Supplier是一个函数式接口,所以可以传递Lambda表达式
            System.out.println(getString(()-> "ss"));
        }
    }
    

    5、Consumer接口

    java.util.function.Consumer<T>接口则正好与Supplier接口相反,
    它不是生产一个数据,而是消费一个数据,其数据类型由泛型决定。
    Consumer接口中包含抽象方法void accept(T t),意为消费一个指定泛型的数据。
    Consumer接口是一个消费型接口,泛型执行什么类型,就可以使用accept方法消费什么类型的数据
    至于具体怎么消费(使用),需要自定义(输出,计算....)

    public class Demo01Consumer {
        public static void main(String[] args) {
            method("明细", (String name)->{
                // 翻转字符串
                String s = new StringBuilder(name).reverse().toString();
                System.out.println(s);
            });
        }
        // 传递一个字符串的姓名
        public static void method(String name, Consumer<String> con) {con.accept(name);}
    }
    

    1、Consumer接口的默认方法andThen
    作用:需要两个Consumer接口,可以把两个Consumer接口组合到一起,在对数据进行消费
    例如:
    Consumer<String> con1
    Consumer<String> con2
    String s = "hello";
    con1.accept(s);
    con2.accept(s);
    连接两个Consumer接口 再进行消费
    con1.andThen(con2).accept(s); 谁写前边谁先消费

    public class Demo02AndThen {
        public static void main(String[] args) {
            method("Hello",
                    (t)->{System.out.println(t.toLowerCase());},
                    (t)->{System.out.println(t.toUpperCase());});
        }
        public static void method(String s, Consumer<String>con1, Consumer<String>con2) {
    //        con1.accept(s);
    //        con2.accept(s);
            // 使用andThen方法,把两个Consummer接口连接到一起,在消费数据
            con1.andThen(con2).accept(s); // con1连接con2,先执行con1消费数据,在执行con2消费数据
        }
    }
    

    2、练习,利用Consumer打印数组中的年龄性别

    public class Demo03Test {
        public static void printInfo(String[] arr, Consumer<String>con1, Consumer<String>con2) {
            for(String message: arr) {
                con1.andThen(con2).accept(message);
            }
        }
        public static void main(String[] args) {
            String[] arr = {"下面,女", "上面,男", "左面,女", "右面,男"};
            printInfo(arr, (msg)->{
                String name = msg.split(",")[0];
                System.out.print("姓名:" + name + ",");
            },(msg)->{
                String name = msg.split(",")[1];
                System.out.println("性别:" + name);
            });
        }
    }
    /*
    姓名:下面,性别:女
    姓名:上面,性别:男
    姓名:左面,性别:女
    姓名:右面,性别:男
    */
    

    6、Predicate

    java.util.function.Predicate<T>接口
    作用:对某种数据类型的数据进行判断,结果返回一个boolean值
    Predicate接口中包含一个抽象方法:
    boolean test(T t):用来对指定数据类型数据进行判断的方法
    结果:
    符合条件,返回true
    不符合条件,返回false

    public class Demo01Predicate {
        public static void main(String[] args) {
            String s = "abcd";
            boolean b = checkString(s, (str)-> {
                return str.length() > 5; // 判断传入的字符串是否大于5
            });
        }
        public static boolean checkString(String s, Predicate<String> pre) {
            return pre.test(s);
        }
    }
    

    1、默认方法:and
    Predicate接口中有一个方法and,表示并且关系,也可以用于连接两个判断条件

    /*
    default Predicate<T> and(Predicate<? super T> other) {
            Objects.requireNonNull(other);
            return (t) -> this.test(t) && other.test(t);
    }
    */
    public class Dem02Predicate_and {
        public static void main(String[] args) {
            String s = "abcdef";
            boolean b = checkString(s, (str)->{
                return str.length() > 5;
            }, (str)->{
                return str.contains("a");
            });
            System.out.println(b);
        }
        public static boolean checkString(String s, Predicate<String> pre1, Predicate<String>pre2) {
    //        return pre1.test(s) && pre2.test(s);
            return pre1.and(pre2).test(s);
        }
    }
    

    2、默认方法:or
    Predicate接口中有一个方法or,表示或者关系,也可以用于连接两个判断条件

    public class Demo03Predicate_or {
        public static void main(String[] args) {
            String s = "abcdef";
            boolean b = checkString(s, (str)->{
                return str.length() > 5;
            }, (str)->{
                return str.contains("s");
            });
            System.out.println(b);
        }
        public static boolean checkString(String s, Predicate<String> pre1, Predicate<String>pre2) {
    //        return pre1.test(s) || pre2.test(s);
            return pre1.or(pre2).test(s);
        }
    }
    

    3、默认方法:negate
    Predicate接口中有一个方法negate,也表示取反的意思

    public class Demo04Predicate_negate {
        public static void main(String[] args) {
            String s = "abcdef";
            boolean b = checkString(s, (str)-> {
                return str.length() > 5;
            });
            System.out.println(b);
        }
        public static boolean checkString(String s, Predicate<String> pre) {
            //return !pre.test(s);
            return pre.negate().test(s);
        }
    }
    

    4、练习:集合信息筛选
    请通过Predicate接口的拼装将符合要求的字符串筛选到集合ArrayList中,
    需要同时满足两个条件:

    1. 必须为女生;
    2. 姓名为3个字。
    public class Demo05Test {
        public static void main(String[] args) {
            String[] arr = {"刘德华,男", "周华健,男", "张惠妹,女"};
            ArrayList<String> list = filter(arr, (s)->{
                return s.split(",")[1].equals("女");
            }, (s)->{
                return s.split(",")[0].length() == 3;
            });
            System.out.println(list);
        }
        public static ArrayList<String> filter(String[] arr, Predicate<String>pre1, Predicate<String>pre2) {
            ArrayList<String> list = new ArrayList<>();
            for (String s : arr) {
                // 使用predicate接口中的方法test对获取到的字符串进行判断
                boolean b = pre1.and(pre2).test(s);
                if (b) {
                    list.add(s);
                }
            }
            return list;
        }
    }
    

    7、Function接口

    java.util.function.Function<T,R>接口用来根据一个类型的数据得到另一个类型的数据,
    前者称为前置条件,后者称为后置条件。
    Function接口中最主要的抽象方法为:R apply(T t),根据类型T的参数获取类型R的结果。
    使用的场景例如:将String类型转换为Integer类型。

    public class Demo01Function {
        public static void change(String s, Function<String, Integer> fun) {
            Integer in = fun.apply(s);
            System.out.println(in);
        }
        public static void main(String[] args) {
            String s = "1234";
            change(s, (String str)->{
                return Integer.parseInt(str);
            });
            change(s, str->Integer.parseInt(str));
        }
    }
    

    1、默认方法:andThen
    Function接口中的默认方法andThen:用来进行组合操作

    public class Demo2Function {
        public static void change(String s, Function<String, Integer> fun1, Function<Integer, String> fun2) {
            String str = fun1.andThen(fun2).apply(s);
            System.out.println(str);
        }
        public static void main(String[] args) {
            String s = "123";
            change(s,(str)-> {
                return Integer.parseInt(str) + 10;
            }, (i)-> {
                return i.toString();
            });
        }
    }
    

    相关文章

      网友评论

          本文标题:[java]18、函数式接口

          本文链接:https://www.haomeiwen.com/subject/oskzoltx.html