java新特性-函数式接口-作为方法参数-作为方法的返回值-常用函数式接口-Supplier-Consumer-Predicate-Function

文章目录

    • 函数式接口
      • 概念
        • 函数式接口作为方法参数
        • 函数式接口作为方法的返回值
        • 常用函数式接口
          • Supplier接口
          • 常用函数式接口 Consumer
          • 函数式接口之 Predicate接口
          • 常用接口之Function 接口

函数式接口

概念

  • 函数式接口 = 有且仅有一个抽象方法的接口;
  • java中的函数式编程体现的就是Lambda表达式 = 函数式接口可以适用于Lambda使用的接口;
  • java的Lambda表达式使用的前提 = 保证接口中有且仅有一个抽象方法。

小知识点:

  • 子类重写父类方法,会有注解@Override。
  • 函数式接口 的注解是 @FunctionalInterface,检测是不是函数式接口。

案例:

public class MyInterfaceDemo {
    public static void main(String[] args) {
        // 函数式接口可以用作方法的参数传递
        // 是不是说Lambda表达式啊
        useShow(()-> System.out.println("方法的参数传递"));

        // 函数式接口用作局部变量
        MyInterface my = () -> System.out.println("局部变量");
        // 将Lambda表达式 赋值给 函数式接口
        // 上述等价于
  /*      MyInterface my = new MyInterface() {
            @Override
            public void show() {
                System.out.println("局部变量");
            }
        };*/
        my.show();
        
    }
    private static void useShow(MyInterface mif){
        mif.show();
    }
}
函数式接口作为方法参数

如果方法的参数是一个函数式接口,可以使用Lambda表达式作为参数传递。

	startThread(() -> System.out.println(Thread.currentThread().getName() + ""));

需求:
类(RunnableDemo),两个方法:startThread(Runnable r)方法参数Runnable是一个函数式接口;
main主方法,调用startThread方法

public class RunnableDemo {
    public static void main(String[] args) {
        // 调用startThread方法


        // 匿名内部类的方式
        startThread(new Runnable() {
            @Override
            public void run() {
                System.out.println(Thread.currentThread().getName() + "线程启动了");
            }
        });
        // Lambda表达式 的方式
        startThread(() -> System.out.println(Thread.currentThread().getName() + "线程启动了"));

        
    }
    private static void startThread(Runnable r){
       /* Thread t = new Thread(r);
        t.start();*/
        // 简写
        new Thread(r).start();
        // 也就是线程的启动
    }
}
函数式接口作为方法的返回值

如果方法的返回值是一个函数式接口,使用Lambda表达式作为结果返回。

匿名内部类:
private static Comparator<String> getComparator(){
	return (s1,s2) -> s1.length()-s2.length();
	}

需求:
类(ComparatorDemo),两个方法:
Comparator< String >getComparator() 方法返回值Comparator是一个函数式接口
主方法main,调用getComparator方法

public class ComparatorDemo {
    /*
    类(ComparatorDemo),两个方法:
															Comparator< String >getComparator() 方法返回值Comparator是一个函数式接口
															主方法main,调用getComparator方法
															*/
    public static void main(String[] args) {

        // 创建集合,存储字符串字符
        ArrayList<String> array = new ArrayList<String>();

        array.add("cccc");
        array.add("aa");
        array.add("b");
        array.add("ddd");

        System.out.println("排序前:" + array);
        // 输出内容是:排序前:[cccc, aa, b, ddd]
        // 就是按照集合添加的顺序。

        // 自然排序 按照自然排序。
        Collections.sort(array);
        System.out.println("排序后:" + array);
        // 输出内容:排序后:[aa, b, cccc, ddd]

        //
        Collections.sort(array, getComparator());
        System.out.println("排序后1:" + array);
    }
    private static Comparator<String> getComparator(){
        // 返回值是Comparator的实现类对象
        // 使用匿名内部类的形式
  /*      Comparator c = new Comparator(){
            @Override
            public int compare(String s1, String s2) {
                return s1.length() - s2.length();
            }
        };
        return c;*/

        // 改进 省略 这里使用的是匿名内部类的方式。
//        return new Comparator() {
//            @Override
//            public int compare(String s1, String s2) {
//                return s1.length() - s2.length();
//                // 正数 s1待比较数据 s2是已存在的数据
//                // 也就是 长的数据放在后面
//            }
//        };
        // 改进 使用Lambda表达式
//        return (String s1,String s2) -> {
//            return s1.length() - s2.length();
//        };
        // 省略形式
        return (s1,s2) -> s1.length()-s2.length();
    }
}
常用函数式接口

java 8 在java.util.function包下预定了大量的函数式接口供使用
四个接口: Supplier接口、Consumer接口、Predicate接口、Function接口。

接口名 说明
Supplier< T > 产生一个T类型的数据
Consumer< T > 接收一个T类型的数据
Predicate< T > 判断T类型的参数是否满足指定条件,返回boolean类型
Function< T,R > 输入T类型的参数,输出R类型的参数,按照指定的操作完成
Supplier接口

概述:

  • 在java.util.function包下,使用需要导包
  • 代表接口供应商,主要用来生产数据
  • Supplier< T > :包含一个无参的方法,T表示泛型
  • T get() : 获取结果,该方法不需要参数,它会按照某种实现逻辑(由Lambda表达式实现)返回一个数据
  • Supplier< T > 接口被称为生产型接口,制定了接口的泛型是什么类型,接口中的get方法就会产生什么类型的数据

案例:

public class SupplierDemo {
    public static void main(String[] args) {
        // getString 方法的参数是函数式接口,那么实际上传递的是接口的实现类对象。
        // 只有一个方法get,
        // 匿名内部类形式
        String st = getString(new Supplier<String>() {
            @Override
            public String get() {
                return "you";
            }
        });
        System.out.println(st);
        // Lambda表达式形式
        String s = getString(()->{
            return "sunshine";
        });
        System.out.println(s);
        // 省略
        String name = getString(() -> "汪苏泷");
        System.out.println(name);

        Integer i = getInteger(() -> 30);
    }
    // 定义方法,返回一个字符串
    private static String getString(Supplier<String> sup){
        return sup.get();
    }
    // 定义方法,返回一个整数
    private static Integer getInteger(Supplier<Integer> sup){
        return sup.get();
    }
}

练习:
需求:
类(SupplierTest),两个方法:int getMax(Supplier< Integer > sup)用于返回一个int数组中的最大值;
main方法 调用getMax方法。

public class SupplierTest {
    public static void main(String[] args) {
        /*
        类(SupplierTest),两个方法:
        int getMax(Supplier< Integer > sup)用于返回一个int数组中的最大值;
        main方法 调用getMax方法。
													*/
        int[] array = {19,50,28,27,46};
        int MaxValue = getMax(() -> {
            int max = array[0];
            for(int i = 1; i < array.length ; i++){
                if(array[i] > max){
                    max = array[i];
                }
            }
            return max;
        });
        System.out.println(MaxValue);
    }
    private static Integer getMax(Supplier<Integer> sup){
        return sup.get();
        // 具体的操作 还得Lambda表达式 进行设置
    }
}
常用函数式接口 Consumer

概念:

  • 在java.util.function包下,使用需要导包
  • 是一个消费型的接口,消费的类型由泛型指定,接收单个输入参数并且不返回结果
  • Consumer< T >有两个方法:
方法名 说明
void accept(T t) 对给定的参数执行此操作
此操作最终是在Lambda表达式中实现的
default Consumer< T > andThen(Consumer < ? super T > after)
default Consumer< T > andThen (Consumer after)
返回一个组成的Consumer,依次执行此操作,然后执行after操作
案例:
public class ConsumerDemo {
    public static void main(String[] args) {
        // 调用operatorString方法
        operatorString("汪苏泷", (String s)->{
            System.out.println(s);
        });
        // 省略
        operatorString("许嵩", s -> System.out.println(s));
        // 方法引用的形式 引用类的方法 类::静态方法
        operatorString("林俊杰", System.out::println);

        // 将输出内容翻转
        operatorString("周杰伦", s -> {
            System.out.println(new StringBuilder(s).reverse().toString());
        });
        System.out.println("------------------");
        operatorString1("胡夏", s-> System.out.println(s), s-> System.out.println(new StringBuffer(s).reverse().toString()));
    }
    // 定义方法,消费一个字符串
    private static void operatorString(String name, Consumer<String> con){
        con.accept(name);
        // 具体的操作由Lambda表达式书写
    }
    // 定义方法 ,用不同的方式消费同一个字符串数据两次
    // 也就是有两个Consumer接口
    private static void operatorString1(String name,Consumer<String> con1,Consumer<String> con2){
//        con1.accept(name);
//        con2.accept(name);
        // 使用andThen改进
        con1.andThen(con2).accept(name);
/*    default Consumer andThen(Consumer after) {
        Objects.requireNonNull(after);
        return (T t) -> { accept(t); after.accept(t); };
    }
    */
    }
}

练习:
要求:
String[] strArray = {“汪苏泷,30”,“许嵩,32”,“胡夏,32”};
字符串数组中有多条信息,请按照格式:“姓名:xx,年龄:xx”的格式输出打印
把打印姓名的动作 第一个 Consumer 接口的Lambda实例
把打印年龄的动作 第二个 Consumer 接口的Lambda实例
将两个Consumer接口按照顺序组合到一起使用

public class ConsumerTest {
    /*字符串数组中有多条信息,请按照格式:“姓名:xx,年龄:xx”的格式输出打印
    把打印姓名的动作 第一个 Consumer 接口的Lambda实例
    把打印年龄的动作 第二个 Consumer 接口的Lambda实例
    将两个Consumer接口按照顺序组合到一起使用
    */
    public static void main(String[] args) {
        String[] strArray = {"汪苏泷,30","许嵩,32","胡夏,32"};
        // 自己的
        for(String str:strArray){
            printNameAge(str, s -> {
                String name = s.split(",")[0];
                System.out.print("姓名:" + name);
            },s->{
                String age = s.split(",")[1];
                System.out.println(",年龄:" + age);
            });
        }
        System.out.println("---------------");
        // 视频中的
        printInfo(strArray, s->{
            String name = s.split(",")[0];
            System.out.print("姓名:" + name);
        }, s->{
            String age = s.split(",")[1];
            System.out.println(",年龄:" + age);
        });
    }
    // 自己的想法
    private static void printNameAge(String str, Consumer<String> con1,Consumer<String> con2){
        con1.andThen(con2).accept(str);
    }
    // 视频中想法
    private static void printInfo(String[] strArray,Consumer<String> con1,Consumer<String>con2){
        for(String str:strArray){
            con1.andThen(con2).accept(str);
        }
    }
}
函数式接口之 Predicate接口

概念:

  • 在java.util.funciton包下,使用需要导包
  • Predicate接口 表示参数的谓词(布尔值函数),对参数进行判断,返回一个布尔值。
  • Predicate< T > 接口通常用于判断参数是否满足指定的条件
  • Predicate< T > 有常用的四个方法:
方法名 说明
boolean test(T t) 对给定的参数进行判断(判断逻辑由Lambda表达式实现),返回一个布尔值
Predicate对象.test()
default Predicate< T > negate() 返回一个逻辑的否定,对应逻辑非
Predicate对象.negate().test()
default Predicate< T > and(Predicate other) 返回一个组合判断,对应短路与
Predicate对象1.and(Predicate对象2).test()
default Predicate< T > or(Predicate other) 返回一个组合判断,对应短路或
Predicate对象1.or(Predicate对象2).test()
案例:
public class PredicateDemo {
    public static void main(String[] args) {
        // 调用checkString方法
        boolean b = checkString("sun",(String str)->{
            return str.length() > 5;
        });
        System.out.println(b);
        boolean b1 = checkString("sunshine", str -> str.length() > 5);
        System.out.println(b1);
    }
    // 判断给定的字符串是否满足要求
    private static boolean checkString(String s, Predicate<String> pre){
//        return pre.test(s);
        // 具体的实现在 调用它的Lambda表达式中实现

        // 想实现逻辑非的操作
//        return !pre.test(s);
        // 不是使用上述形式,而是采用negate方法,且negate方法得在test方法之前
        return pre.negate().test(s);
    }
}

案例:

public class PredicateDemo2 {
    public static void main(String[] args) {
        boolean b1 = checkString("sun", s->s.length()>2);
        System.out.println(b1);
        boolean b2 = checkString("sunshine", s->s.length()<5);
        System.out.println(b2);
        System.out.println("--------------");
        boolean b3 = checkStringAdd("hello", s->s.length()>6, s1 -> s1.length() <15);
        System.out.println(b3);
}
    // 同一个字符串做两个不同的判断,并将两个判断结果做逻辑与的结果作为最终输出结果
    private static boolean checkStringAdd(String s ,Predicate<String> pre1,Predicate<String> pre2){
//        boolean b1 = pre1.test(s);
//        boolean b2 = pre2.test(s);
//        boolean b = b1 && b2;
//        return b;
        // 实现短路与 可以使用方法and
//        return pre1.and(pre2).test(s);
        /*default Predicate and(Predicate other) {
            Objects.requireNonNull(other);
            return (t) -> test(t) && other.test(t);
        }*/
        // 实现短路或 可以使用方法or
        return pre1.or(pre2).test(s);
        /*default Predicate or(Predicate other) {
            Objects.requireNonNull(other);
            return (t) -> test(t) || other.test(t);
        }*/

    }

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

练习:
需求:
String[] strArray = {“汪苏泷,30”,“许嵩,34”,“林俊杰,35”,“胡夏,31”,“周杰伦,33”};
字符串数组中有多条信息,请通过Predicate接口的拼接将符合要求的字符串筛选到集合ArrayList中,并遍历ArrayList集合
同时满足要求:姓名长度大于2;年龄大于33;

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

        String[] strArray = {"汪苏泷,30","许嵩,34","林俊杰,35","胡夏,31","周杰伦,33"};
        // 自己写的方法:方法1
//        ArrayList array = new ArrayList();
//        for(String s:strArray){
//            boolean b = checkName(s, (String s1) -> {
//                String name = s1.split(",")[0];
//                return name.length()>2;
//            }, (String s2)->{
//                int age = Integer.parseInt(s2.split(",")[1]);
//                return age>33;
//            });
//            if(b){
//                array.add(s);
//            }
//        }
//        for(String s:array){
//            System.out.println(s);
//        }
        // 方法2 
        ArrayList<String> arr = checkName2(strArray,(String s)->{
            String name = s.split(",")[0];
            return name.length() >2;
        },(String s2)->{
            int age = Integer.parseInt(s2.split(",")[1]);
            return age>33;
        });
        for(String s:arr){
            System.out.println(s);
        }

    }
    
    // 自己写的 方法1
    private static boolean checkName(String str, Predicate<String> pre1, Predicate<String> pre2){
            return pre1.and(pre2).test(str);
    }
    // 通过Predicate接口的拼接将符合要求的字符串筛选到集合ArrayList中,并遍历ArrayList集合 方法2
    private static ArrayList<String>checkName2(String[] strs,Predicate<String> pre1,Predicate<String> pre2){
        // 定义集合
        ArrayList<String> arr = new ArrayList<String>();

        // 遍历String数组
        for(String s:strs){
            if(pre1.and(pre2).test(s)){
                arr.add(s);
            }
        }
        return arr;
    }
}
常用接口之Function 接口

概念:

  • 在java.util.function包下,使用需要导包
  • Interface Function< T , R > T 是函数输入的类型,R 是函数输出的类型,表示接收一个参数 并产生结果 的函数
  • Function< T,R>接口通常用于对参数进行处理,转换(处理逻辑由Lambda表达式实现),然后返回一个新的值
  • Function< T,R>常用的两个方法:
方法名 说明
R apply(T t) 将此函数应用于给定的参数
default < V > Function andThen(Function after) 返回一个组合函数,首先将该函数应用于输入,然后将after函数应用于结果
案例:
public class FunctionDemo {
    public static void main(String[] args) {
        // 方法1
        convertInt("1024", (String s)->{
            return Integer.parseInt(s);
        });
        // 优化
        convertInt("2048",s -> Integer.parseInt(s));

        // 方法2
        convertString(924, (Integer i)->{
            return String.valueOf(i+100);
        });
        // 方法3 自己的
        convertStrToIntToString("1022", s->{
            return String.valueOf(Integer.parseInt(s) + 1000);
        });
        // 方法3 视频中的
        convertStrToIntToString("1000", s->Integer.parseInt(s)+24,i->String.valueOf(i));
    }
    // 定义一个方法,把一个字符串转换为int类型,在控制台输出 方法1
    private static void convertInt(String s, Function<String,Integer> fun){
        Integer i = fun.apply(s);
        System.out.println(i);
    }
    // 方法2 把一个int类型的数 加上一个整数之后,转为字符串在控制台输出
    private static void convertString(Integer i,Function<Integer,String> fun){
        String s = fun.apply(i);
        System.out.println(s);
    }
    // 方法3 把一个字符串转为int类型,加上一个整数之后,转为字符串在控制台输出 自己的
    private static void convertStrToIntToString(String st,Function<String,String> fun){
        String str = fun.apply(st);
        System.out.println(str);
    }
    // 方法3 把一个字符串转为int类型,加上一个整数之后,转为字符串在控制台输出 自己的
    private static void convertStrToIntToString(String s,Function<String,Integer> fun1,Function<Integer,String> fun2){
//        Integer i = fun1.apply(s);
//        String ss = fun2.apply(i);
//        System.out.println(ss);
        // 使用andThen方法改进
        String ss = fun1.andThen(fun2).apply(s);
        System.out.println(ss);
        /*    default  Function andThen(Function after) {
            Objects.requireNonNull(after);
            return (T t) -> after.apply(apply(t));
        }
*/
    }
}

练习:
需求:
String s = “汪苏泷,30”;
操作:①字符串截取得到数字年龄部分;②将数字年龄字符串转为int类型的数据;③数据加70,在控制台输出

public class FunctionDemo2 {
    public static void main(String[] args) {
        String s = "汪苏泷,30";
        // xhj
        sumAge(s, s1 -> {
            String age = s.split(",")[1];
            return Integer.parseInt(age ) + 70;
        });
        // video
        convert(s, s1 -> s.split(",")[1],s2 -> Integer.parseInt(s2), i -> i + 70);

    }
    // xhj
    private static void sumAge(String s, Function<String,Integer> fun1){
        Integer i = fun1.apply(s);
        System.out.println(i);
    }
    // video
    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);
    }
}

你可能感兴趣的:(java学习,java,开发语言)