zoukankan      html  css  js  c++  java
  • 函数式接口的使用 (Function、Predicate、Supplier、Consumer)

    参考:https://blog.csdn.net/jmj18756235518/article/details/81490966

    函数式接口

    定义:有且只有一个抽象方法的接口

    Function<T, R>: y = f(x) T: x 输入参数, R: 返回结果,y

    所有标注了@FunctionalInterface注解的接口都是函数式接口,所有标注了该注解的接口都将能用在lambda表达式上

    特点:通过传入不同的Function,实现了在同一个方法中实现不同的操作,在实际开发中可以大大减少很多重复的代码。

    例如:新增用户的功能,用户分为VIP和普通用户,且有两种不同的新增逻辑。那么此时我们就可以先写两种不同的逻辑。除此之外,这样还让逻辑与数据分离开来,我们可以实现逻辑的复用。

    函数式编程与非函数式编程的区别

    函数式编程: 先考虑传入的参数,再考虑方法的实现

    非函数式编程:先定义好方法,再传入指定的参数

    /**
     * 需求
     * 1.定义一个函数式接口CurrentTimePrinter,其中抽象方法void printCurrentTime(),使用注解@FunctionalInterface
     * 2.在测试类中定义static void showLongTime(CurrentTimePrinter timePrinter),该方法的预期行为是使用timePrinter打印系统当前毫秒值
     * 3.测试showLongTime(),通过lambda表达式完成需求
     */
    @FunctionalInterface
    public interface CurrentTimePrinter {
        void printCurrentTime();
    }
    
    测试类
    public class FunctionalInterfaceTest {
        /**
         * 打印当前系统的毫秒值
         * @param timePrinter
         */
        public static void showLongTime(CurrentTimePrinter timePrinter){
            timePrinter.printCurrentTime();
        }
    
        public static void main(String[] args) {
            showLongTime(() -> System.out.println(System.currentTimeMillis()));
        }
    }
    
    
    
    /**
     * 需求
     * 1.定义一个函数式接口IntCalc,其中抽象方法int calc(int a , int b),使用注解@FunctionalInterface
     * 2.在测试类中定义static void getProduct(int a , int b ,IntCalc calc), 该方法的预期行为是使用calc得到a和b的乘积并打印结果
     * 3.测试getProduct(),通过lambda表达式完成需求
     */
    @FunctionalInterface
    public interface IntCalc {
        int calc(int a , int b);
    }
    
    测试类:
    /**
     * 需求
     * 定义static void getProduct(int a , int b ,IntCalc calc), 该方法的预期行为是使用calc得到a和b的乘积并打印结果
     */
    public class FunctionalInterfaceTest02 {
        static void getProduct(int a , int b ,IntCalc calc){
           int result = calc.calc(a, b);
            System.out.println(result);
        }
    
        public static void main(String[] args) {
            getProduct(2,3, (a, b) -> a*b);
        }
    }
    

    静态方法的引用

    /**
     * 1.定义一个函数式接口NumberToString,其中抽象方法String convert(int num),使用注解@FunctionalInterface
     * 2.在测试类中定义static void decToHex(int num ,NumberToString nts), 
     * 该方法的预期行为是使用nts将一个十进制整数转换成十六进制表示的字符串,tips:已知该行为与Integer类中的toHexString方法一致
     * 3.测试decToHex (),使用方法引用完成需求
     */
    @FunctionalInterface
    public interface NumberToString {
        String convert(int num);
    }
    

    测试类

    public class FunctionalInterfaceTest03 {
        /**
         * 需求:
         * 在测试类中定义static void decToHex(int num ,NumberToString nts),
         * 该方法的预期行为是使用nts将一个十进制整数转换成十六进制表示的字符串,tips:已知该行为与Integer类中的toHexString方法一致
         */
        public static void main(String[] args) {
            //NumberToString类的方法的实现使用了Integer 类的toHexString 方法
            decToHex(999, Integer::toHexString);
        }
        public static void decToHex(int num ,NumberToString nts){
            String convert = nts.convert(num);
            System.out.println(convert);
        }
    }
    

    使用函数式编程来实现延迟加载

    Predicate的使用(构造断言式):

    简介:predicate是一个接口,含有一个抽象方法test(),含有4个由default修饰的具体实现方法and()、or()、negate()、isEquals()

    and()对应java的连接符 &&;

    or()对应java的连接符 || ;

    negate()对应java的连接符 ! ;

    isEquals对应java的连接符 == ;

    package com.test.stream;
    
    /**
     * @program: basic-java
     * @Author:chenxuebing
     * @Date:2019-09-16 9:25
     * @Description:(描述)
     */
    
    import java.util.function.Predicate;
    
    /**
     * 需求:1.请在测试类main方法中完成以下需求
     * 已知有Integer[] arr = {-12345, 9999, 520, 0,-38,-7758520,941213}
     * a)使用lambda表达式创建Predicate对象p1,p1能判断整数是否是自然数(大于等于0)
     * b)使用lambda表达式创建Predicate对象p2,p2能判断整数的绝对值是否大于100
     * c)使用lambda表达式创建Predicate对象p3,p3能判断整数是否是偶数
     *
     * 	遍历arr,仅利用已创建的Predicate对象(不使用任何逻辑运算符),完成以下需求
     * i.打印自然数的个数
     * ii.打印负整数的个数
     * iii.打印绝对值大于100的偶数的个数
     * iv.打印是负整数或偶数的数的个数
     */
    public class Test01 {
        public static void main(String[] args) {
            Integer[] arr = {-12345, 9999, 520, 0,-38,-7758520,941213};
            Predicate<Integer> p1 = (t) -> t >= 0;
            Predicate<Integer> p2 = (t) -> Math.abs(t) > 100;
            Predicate<Integer> p3 = (t) -> t % 2 == 0;
            int count1 = 0;
            int count2 = 0;
            int count3 = 0;
            int count4 = 0;
            for(int a : arr){
                //自然数个数
                if(p1.test(a)){
                   count1++;
                }
                //绝对值大于100的偶数的个数
                if(p2.and(p3).test(a)){
                    count2++;
                }
                //负整数的个数
                if(p1.negate().test(a)){
                    count3++;
                }
                //负整数或偶数的数的个数
                //先找满足条件的负整数,再找满足条件的偶数,然后取交集,p1.negate(),!p1.test(),p3.test()取交集
                if(p1.negate().or(p3).test(a)){
                    count4++;
                }
            }
            System.out.println("自然数"+ count1);
            System.out.println("绝对值大于100的偶数的个数"+ count2);
            System.out.println("负整数的个数"+ count3);
            System.out.println("负整数或偶数的数的个数"+ count4);
        }
    }
    

    Function接口的使用

    简介:含有一个抽象方法R apply(T t), 两个default修饰的实现了的方法compose(), andThen()

    特点:

    f1.compose(f2).apply(T) : 先执行f2.apply(T), 再执行f1.apply(f2.apply(T))

    compose接收一个Function参数,返回时先用传入的逻辑执行apply,然后使用当前Function的apply

    f1.andThen(f2).apply(T): 先执行f1.apply(T) , 再执行分f2.apply(f1.apply(T))

    andThen跟compose正相反,先执行当前的逻辑,再执行传入的逻辑。

    /**
     * 需求
     * 1.使用lambda表达式分别将以下功能封装到Function对象中
     * a)求Integer类型ArrayList中所有元素的平均数
     * b)将Map<String,Integer>中value存到ArrayList<Integer>中
     * 2.已知学生成绩如下
     * 姓名	成绩
     * 岑小村	59
     * 谷天洛	82
     * 渣渣辉	98
     * 蓝小月	65
     * 皮几万	70
     * 3.以学生姓名为key成绩为value创建集合并存储数据,使用刚刚创建的Function对象求学生的平均成绩
     */
    public class FunctionTest {
        public static void main(String[] args) {
            //使用Lambda表达式求Integer类型ArrayList中所有元素的平均数
            Function<ArrayList<Integer>, Integer> f1 = (list) -> {
                int sum = 0;
                int count = 0;
                for(Integer score : list){
                    sum += score;
                    count++;
                }
                return sum/count;
            };
            //使用Lambda表达式将Map<String,Integer>中value存到ArrayList<Integer>中
            Function<Map<String, Integer>, ArrayList<Integer>> f2 = (map) -> {
                ArrayList<Integer> scoreList = new ArrayList<>();
                Collection<Integer> values = map.values();
                for(Integer score : values){
                    scoreList.add(score);
                }
                return scoreList;
            };
    
            //以学生姓名为key成绩为value创建集合并存储数据
            Map<String,Integer> map = new HashMap<String, Integer>();
            map.put("岑小村", 59);
            map.put("谷天洛", 82);
            map.put("渣渣辉", 98);
            map.put("蓝小月", 65);
            map.put("皮几万", 70);
            //使用刚刚创建的Function对象求学生的平均成绩
            //f1.compose(f2).apply(map),先求f2.apply(map),再求     f1.apply(f2.apply(map)),f2.apply(map)的返回值作为f1的apply的参数值
            int averge = f1.compose(f2).apply(map);
            System.out.println(averge);
        }
    
    }
    

    Supplier接口(生产者)

    简介:Supplier函数式接口

            T get()抽象方法,返回一个T类型的对象
    
    import java.util.function.Supplier;
    
    /**
     * Supplier函数式接口
     * 抽象方法 T get(): 返回一个T类型的对象
     */
    public class SupplierTest {
        //Supplier<String> supplier 的泛型为String,那么它的get 方法返回对象也是一个String类型
        public static String getString(Supplier<String> supplier){
            return supplier.get();
        }
    
        public static void main(String[] args) {
            //若方法体只有一条语句可以省略{} 和 return
            String result = getString(() -> "胡歌");
            System.out.println(result);
        }
    }
    

    Consumer接口(消费者)

    import java.util.function.Consumer;
    
    /**
     * Consumer函数式编程接口
     * void accept(T t)方法, 用来做消费
     */
    public class ConsumerTest {
        //对String类型的对象进行消费
        public static void method(String name, Consumer<String> consumer){
            consumer.accept(name);
        }
    
        public static void main(String[] args) {
            //对name,进行消费,反转打印姓名
            method("赵丽颖", name -> {
               StringBuilder builder = new StringBuilder();
               builder.append(name);
                System.out.println(builder.reverse().toString());
            });
        }
    }
    

    andThen()方法

    /**
     * andThen(Consumer)
     * consumer1.andThen(consumer2).accept(T)
     * 先执行consumer1.accept(T),再执行consumer2.accept(T),因为T是对象,consumer1对对象进行消费后对象发生变化
     * 随着consumer2消费的对象是consumer1消费后的对象
     */
    public class ConsumerAndThenTest {
        public static void method (int[] arr, Consumer<int[]> consumer1, Consumer<int[]> consumer2){
            consumer1.andThen(consumer2).accept(arr);
        }
    
        public static void main(String[] args) {
            method(new int[]{1, 3, 5, 6},
                    //将数组的第一个元素改为0
                    arr -> {
                        System.out.println( arr[1] = 0);
                        System.out.println(arr.toString());
                    },// 0, 3, 5, 6
                    //将数组的第一个元素改为1
                    arr -> {
                        System.out.println(arr[2] = 2); // 2, 3, 5, 6
                        System.out.println(arr[1]);
                    }
                    );
        }
    }
    金麟岂能忍一世平凡 飞上了青天 天下还依然
  • 相关阅读:
    关于“云计算”
    实现工作流至少需要几张表?
    BPI (业务流程改进)项目的管理沙龙笔记
    对“设计”工作在流程中的重新定位
    面向。。。驱动
    定个小目标
    Redis源码分析Sentinel(1)Sentinel服务器
    Redis源码分析Sentinel(3)主观下线与客观下线
    Redis源码分析Sentinel(2)实例处理的Monitor half
    Redis源码分析Sentinel(4)实例处理的Acting half
  • 原文地址:https://www.cnblogs.com/Auge/p/11528974.html
Copyright © 2011-2022 走看看