Java SE-函数式接口及函数式编程

概述
函数式编程
函数式接口作为方法的参数
函数式接口
Supplier接口
Consumer接口
andThen练习
Predicate接口
Functoin接口
小练习

函数式接口
概念

有且仅有一个抽象方法的接口(可以有其他类型方法,但是仅有一个抽象方法)

  • Java中函数式接口体现就是lamda表达式
语法糖

是指使用更便捷,但是原理不变的代码语法,例如在遍历集合中使用for-each语法,但是代码底部使用迭代器实现

注意事项
  • 使用lamda表达式比使用匿名内部类效率更高,以为不需要生成class文件
函数式编程
函数式接口作为方法的参数
/**
 *    函数式接口:有且仅有一个抽象方法,称为函数式接口
 *                当然可以有其它方法(默认方法,静态、私有等)
 *    @FunctionalInterface 作用
 *        检测接口是否是一个函数式接口
 *        是:编译成功
 *        否:编译失败(接口中的抽象方法不是一个)
 */

public interface MyFunctionalInterface {
    public abstract void method1();

    //void method2();
}

/**
 * @Override 注解
 *    作用:
 *        检测方法是否被重写
 *        是:编译成功
 *        否:编译失败
 */
public class MyFunctionalInterfaceImpl implements MyFunctionalInterface{
    @Override
    public void method1() {

    }
}


/**
 *   函数式接口的使用:一般可以作为方法的参数和返回值类型
 *
 */
public class Demo01 {
    /**
     *   定义一个方法,参数使用函数式接口
     */
    public static void show (MyFunctionalInterface myInter) {
        myInter.method1();
    }

    public static void main(String[] args) {
        //调用show方法,方法参数是一个接口,所以可以穿衣一个实现类对象
        show(new MyFunctionalInterfaceImpl());

        //调用show方法,使用匿名内部类
        show(new MyFunctionalInterface() {
            @Override
            public void method1() {
                System.out.println("使用匿名内部类重写接口中的抽象方法");
            }
        });

        //使用lambda表达式重写
        show(()-> System.out.println("使用lamda表达式重写抽象方法"));
    }
}

/**
 *   java.lang.Runnable 接口是一个函数式接口
 *
 */
public class Demo01Runnble {
    /**
     *   定义一个方法,参数为接口类型
     */
    public static void startThread(Runnable run) {
        //开启多线程
        new Thread(run).start();
    }

    public static void main(String[] args) {
        //调用startThread方法,参数为接口类型,传递实现类作为参数
        startThread(()-> System.out.println(Thread.currentThread().getName() + "线程启动了"));
    }
}


函数式接口
import java.util.Comparator;

/**
 *   如果函数的返回值类型是一个函数式接口那么就可以直接返回一个lambda表达式
 */
public class Demo02Comparator {
    /**
     *  定义一个函数,函数的返回值类型为函数式接口
     */
    public static Comparator<String> getComparator() {
//        return new Comparator<String>() {
//            @Override
//            public int compare(String s, String t1) {
//                return s.length() - t1.length();
//            }
//        }

        /**
         *   使用lambda表达式
         */
        return (s,t1)-> s.length()-t1.length();
    }

    public static void main(String[] args) {
        String[] arr = {"aaa", "aa", "lllll"};
        System.out.println(Arrays.toString(arr));
        //调用方法对字符串长度排序
        Arrays.sort(arr, getComparator());
        System.out.println(Arrays.toString(arr));

    }
}
口作为方法的返回值类型

Supplier接口
  • Supplier被称为生产型接口,指定接口的泛型是什么类型,那么接口中的get方法就会返回一个什么类型的数据
  • java.util.function.Supplier 接口中仅包含一个无参的方法: T get().用来获取一个泛型类型指定的参数对象数据
import java.util.function.Supplier;

/**
 *   常用函数式接口
 *       java.util.function.Supplier 接口中仅包含一个无参的方法: T get().用来获取一个泛型类型指定的参数对象数据
 *       Supplier被称为生产型接口,指定接口的泛型是什么类型,那么接口中的get方法就会返回一个什么类型的数据
 *
 */
public class Demo01Supplier {
    /**
     *  定义一个方法,参数传递为接口类型
     */
    public static String getString(Supplier<String> sup) {
        return sup.get();
    }

    public static void main(String[] args) {
        //调用方法,因为方法参数是一个函数式接口,以此可以传递lambda表达式
        String s = getString(()->"好还有");
        System.out.println(s);
    }
}

import java.util.function.Supplier;

/**
 *   练习:求数组元素的最大值
 *       使用Supplier接口作为方法参数类型,通过lambda表达式求出最大值
 *
 */
public class Demo02Test {
    /**
     *  定义一个方法,返回数组元素的最大值方法参数传递Supplier类型接口
     */
    public static int getMax(Supplier<Integer> sup) {
        return sup.get();
    }

    public static void main(String[] args) {
        int[] arr = {6, 4, 2, 1, 78};
        int maxValue = getMax(()-> {
                int max = arr[0];
                for (int e : arr) {
                    if (e > max) {
                        max = e;
                    }
                }
                return max;
            }
        );

        System.out.println(maxValue);
    }
}

Consumer接口
  • Consumer接口是一个消费类型接口,泛型使用什么类型,就可以使用accept方法消费什么类型的数据
  • java.util.function.Consumer 接口正好与Supplier接口相反
import java.util.function.Consumer;

/**
 *   java.util.function.Consumer<T> 接口正好与Supplier接口相反
 *   他不是生产一个数据,而是消费一个数据,数据类型由泛型决定
 *   Consumer<T>接口是一个消费类型接口,泛型使用什么类型,就可以使用accept方法消费什么类型的数据
 *
 */
public class Demo01Consumer {
    /**
     *  定义一个方法
     *  方法的参数传递一个字符串姓名
     *  方法的参数传递Consumer接口泛型使用String
     *  可以使用Consumer接口消费字符串的姓名
     */
    public static void method(String name, Consumer<String> con) {
        con.accept(name);
    }

    public static void main(String[] args) {
        //调用method方法,方法的参数传递字符串姓名,另一个参数是一个Consumer接口 ,可以使用lambda表达式
        method("樊振东", (name)-> {
            //消费方式:直接输出字符串
            //System.out.println(name);

            //消费方式:对字符串进行反转
            String reName = new StringBuilder(name).reverse().toString();
            System.out.println(reName);
        });

    }
}

import javax.crypto.spec.PSource;
import java.util.function.Consumer;

/**
 *   Consumer 接口的默认方法andThen
 *   作用:需要俩个Consumer接口,可以把俩个Consumer接口组合到一起,再对数据进行消费
 *   例如:
 *       Consumer<String> con1
 *       Consumer<String> con1
 *       String s = "hello";
 *       con1.accept(s);
 *       con2.accept(s);
 *       连接来个Consumer接口,再进行消费
 *       con1.andThen(con2).accept(s);   谁先前面谁先消费
 */
public class Demo02AndThen {
    /**
     *   定义一个方法,方法的参数传递一个字符串和俩个接口
     */
    public static void method(String s, Consumer<String> con1, Consumer<String> con2) {
//        con1.accept(s);
//        con2.accept(s);

        //连接俩个Consumer接口,再进行消费(多个接口连接)
        con1.andThen(con2).accept(s);
    }

    public static void main(String[] args) {
        //调用method方法,传递一个字符串俩个lambda表达式
        method("HellO", (t)-> {
            //消费方法:转大写输出
            System.out.println(t.toUpperCase());
        }, (m)-> {
            //消费方式:转小写输出
            System.out.println(m.toLowerCase());
        });
    }
}

andThen练习
import java.util.function.Consumer;

/**
 *    使用andThen打印姓名:年龄
 *    要求将打印的姓名动作作为第一个Consumer接口的lambda实例
 *    打印的性别动作作为第二个Consumer接口的lambda实例
 *     将俩个Consumer接口按照顺序拼接到一起
 */
public class Demo03AndThenTest {
    /**
     *   定义一个方法,传递String类型数据和俩个Consumer接口,使用泛型String
    */
    public static void printInfor(String[] arr, Consumer<String> con1, Consumer<String> con2) {
        //遍历字符串数组
        for (String str : arr) {
            con1.andThen(con2).accept(str);
        }
    }

    public static void main(String[] args) {
        //定义一个字符串类型数组
        String[] arr = {"樊振东,男", "马龙,男", "陈梦,女"};
        printInfor(arr, (message)->{
            //消费方式:以逗号作为分隔符分割
            String name = message.split(",")[0];
            System.out.println("姓名:" + name);
        }, (message)-> {
            //消费方式:以逗号作为分隔符获取性别
            String sex = message.split(",")[1];
            System.out.println("性别:" + sex);
        });
    }
}

Predicate接口
import java.util.function.Predicate;

/**
 *   java.util.function.Predicate<T> 接口
 *   作用:对某种数据类型类型进行判断,结返回一个boolean值
 *   Predicate接口中包含一个抽象方法
 *      boolean test(T t)  对指定数据类型经进行判断
 *      结果:
 *         符合条件,返回true
 *         否则:返回false
 */
public class Demo01Predicate {
    /**
     *   定义一个方法,传递一个String类型字符串,再传递一个接口
     */
    public static boolean checkString(String str, Predicate<String> pre) {
        return pre.test(str);
    }

    public static void main(String[] args) {
        //定义一个字符串
        String str = "好的嘛";
        boolean ans = checkString(str, (s)->{
            //对字符串长度是否大于5
            if (s.length() > 5) {
                return true;
            }
            return false;
        });
        System.out.println(ans);
    }
}

import java.util.function.Predicate;

/**
 *    逻辑表达式,可以连接多个判断条件
 *    && || !
 *    需求:判断一个字符串,有俩个判断条件
 *          1、判断字符串长度是否大于5
 *          2、判断字符串中是否包含a
 *
 */
public class Demo02PredicateAnd {
    /**
     *   定义一个方法,转递一个字符串,俩个接口
     *      一个接口判断一个条件
     */
    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);

        /**
         *  若是或 return pre1.or(pre2).test(s);
         */
        /**
         *  对结果取反 return pre.negate().test(s);
         */
    }

    public static void main(String[] args) {
        String s = "abcdfr";

        boolean ans = checkString(s, (str)->{
            //判断字符串长度是否大于5
            return str.length() > 5;
        }, (str)-> {
            //判断是否包含a
            return str.contains("a");
        });
        System.out.println(ans);
    }
}


练习
import java.util.ArrayList;
import java.util.function.Predicate;

/**
 *   要求:姓名长度必须小于4
 *        必须为女
 */
public class Demo03Test {
    /**
     *   定义一个方法,传递一个字符出纳和俩二接口
     */
    public static ArrayList<String> checkString(String[] arr, Predicate<String> pre1, Predicate<String> pre2) {
        //定义一个集合存储过滤之后的信息
        ArrayList<String> list = new ArrayList<>();
        //遍历字符串数组
        for (String str : arr) {
            //判断是否满足上述条件
            boolean flag = pre1.and(pre2).test(str);
            //满足条件加入集合
            if (flag) {
                list.add(str);
            }
        }
        return list;
    }

    public static void main(String[] args) {
        String[] arr = {"迪丽热巴,女", "杨静,男", "康辉,男", "尼格买提,女", "妮妮,女"};
        //调用过滤方法
        ArrayList<String> list = checkString(arr, (str)-> {
            //名字长度必须小于4
            String name = str.split(",")[0];
            return name.length() < 4;
        }, (str)-> {
            //是否为女
            String sex = str.split(",")[1];
            return sex.equals("女");
        });
        System.out.println(list);

    }
}

Function接口
  • java.util.function.Function<T,R>接口可以用来根据一个类型的数据的得到另一个类型的数据
  • 前者称为前置条件,后者称为后置条件
import java.util.function.Function;

/**
 *   java.util.function.Function<T,R>接口可以用来根据一个类型的数据的得到另一个类型的数据
 *     前者称为前置条件,后者称为后置条件
 *   Function接口最主要的抽象方法为:R apply<T t>  根据类型T的参数,获取R类型的结果
 *     使用场景:如将String类型转换为Integer类型
 */
public class Demo01Function {
    /**
     *  定义一个方法
     *     参数传递一个字符串类型整数
     *     方法的参数传递一个Function接口,泛型使用<String, Integer>
     *      使用Function接口中的方法apply,把字符串类型的整数转换为Integer类型
     */
    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 = "124";
        change(s, (str)-> {
            return Integer.parseInt(s);
        });
    }
}

andThen方法
  • Function 接口中默认方法andThen
  • 作用:将分解的步骤连接在一起
import java.util.function.Function;

/**
 *   Function 接口中默认方法andThen
 *     作用:将分解的步骤连接在一起
 *     需求:把String类型123转换为Integer类型,将转换后的结果加10
 *     把增加后的 结果转换为Integer类型
 *     转化了俩次:
 *         第一次:Integer->String类型
 *         第二次:String->Integer类型
 */
public class Demo01AndThen {
    /**
     *   定义一个方法
     *     参数一个为字符串,另外俩个为接口
     */
    public static void change(String s, Function<String, Integer> fun1, Function<Integer, String> fun2) {
        //将字符串类型转换为Integer类型再转换为字符串类型
        String str = fun1.andThen(fun2).apply(s);
        System.out.println(str);
    }

    public static void main(String[] args) {
        //定义一个字符串类型整数
        String num = "123";
        //调用change方法,传递字符串和俩个lambda表达式
        change(num, (str)-> {
            //将字符串类型转换为整数类型再加上10
            return Integer.parseInt(str) + 10;
        }, (s)-> {
            return s+"";
        });
    }
}


练习
import java.util.function.Function;

/**
 *   练习:自定义函数拼接模型
 *   String str = "赵丽颖,20";
 *   分析:
 *      1、截取字符串年龄部分
 *      2、将字符串类型转换为Integer类型
 *      3、将上一步的int数字累加100
 */
public class Demo02Test {
    /**
     *   定义i一个方法:
     *     参数传递一个字符串,三个接口
     */
    public static void change(String s, Function<String, String> fun1, Function<String, Integer> fun2, Function<Integer, Integer> fun3) {
        //把三个组合到yiqi
        int ans = fun1.andThen(fun2).andThen(fun3).apply(s);
        System.out.println(ans);
    }

    public static void main(String[] args) {
        //定义一个字符串
        String s = "赵丽颖,20";
        //调用change方法,长短地一个字符串,三个接口
        change(s, (str)-> {
            //截取年龄部分
            String age = str.split(",")[1];
            return age;
        }, (str2)-> {
            //将字符串类型转换为int类型
            return Integer.parseInt(str2);
        }, (num)-> {
            //将结果加上100
            return num+100;
        });
    }
}

评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值