函数式接口及其常用的函数式接口

函数式接口概念

函数式接口在java中是指:有且仅有一个抽象方法的接口
当然接口中可以包含其他的方法(默认方法,静态方法,私有方法)

@FunctionalInterface注解:
作用:可以检测接口是否是一个函数式接口
是:编译成功
否:编译失败(①接口中没有抽象方法、②接口中抽象方法的个数不等于一个)
下面是函数式接口的代码案例:

@FunctionalInterface
public interface MyFunctionalInterface {
    public abstract void method();
}

@Override注解:
作用:检测方法是否为重写的方法
是:编译成功
否:编译失败

public class MyFunctionalInterfaceDemo implements MyFunctionalInterface {
    @Override
    public void method() {
        System.out.println("重写接口中的方法");
    }
}
public class Demo {
    //定义一个方法,参数使用函数式接口MyFunctionalInterface
    public static void show(MyFunctionalInterface myInterface) {
        myInterface.method();
    }
    public static void main(String[] args) {
        //调用show方法。方法的参数是一个接口,所以我们可以传递接口的实现类对象
        show(new MyFunctionalInterfaceDemo());

        //调用show方法。方法的参数是一个接口,所以我们可以传递接口的匿名内部类
        show(new MyFunctionalInterface() {
            @Override
            public void method() {
                System.out.println("匿名内部类重写接口中的方法");
            }
        });
        //调用show方法,方法的参数是一个函数式接口,所以我们可以使用Lambda表达式
        show(() -> {
            System.out.println("使用Lambda表达式重写接口中的方法");
        });
        //上句简化为:show(() -> System.out.println("使用Lambda表达式重写接口中的方法"));
    }
}

函数式编程

函数式接口的使用: 一般可以作为方法的参数和返回值类型

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

package com.lushuai.demo03.LambdaTest;
/*
例如java.lang.Runnable接口就是一个函数式接口
假设有一个startThread方法使用该接口作为参数,那么就可以使用Lambda进行传参。
这种情况其实和Thread类的构造方法参数为Runnable没有本质区别
 */
public class Demo01Runnable {
    //定义一个方法startThread,方法的参数使用函数式接口Runnable
    public static void startThread(Runnable run) {
        //开启多线程
        new Thread(run).start();
    }
    public static void main(String[] args) {
        //调用startThread方法,方法的参数是一个接口,所以我们可以传递这个接口的匿名内部类
        startThread(new Runnable() {
            @Override
            public void run() {
                System.out.println(Thread.currentThread().getName()+" --> 线程启动了");
            }
        });
        //调用startThread方法,方法的参数是一个函数式接口,所以我们可以传递Lambda表达式
//        startThread(()->{
//            System.out.println(Thread.currentThread().getName()+" --> 线程启动了");
//        });
        //优化Lambda表达式
        startThread(()-> System.out.println(Thread.currentThread().getName()+" --> 线程启动了"));
    }
}

函数式接口作为方法的返回值类型案例:

package com.lushuai.demo03.LambdaTest;

import java.util.Arrays;
import java.util.Comparator;
/*
如果一个方法的返回值类型是一个函数式接口,那么就可以直接返回一个Lambda表达式
当需要通过一个方法来获取一个java.util.Comparator接口类型的对象作为排序器时,就可以调用该方法获取
 */
public class Demo02Comparator {
    //定义一个方法,方法的返回值使用函数式接口Comparator
    public static Comparator<String> getComparator() {
        //方法的返回值类型是一个接口,那么我们可以返回这个接口的匿名内部类
//        return new Comparator<String>() {
//            @Override
//            public int compare(String o1, String o2) {
//                //按照字符的降序排序
//                return o2.length()-o1.length();
//            }
//        };
        //方法的返回值类型是一个函数式接口,所以我们可以返回一个Lambda表达式
        return (o1, o2) -> o2.length()-o1.length();
    }
    public static void main(String[] args) {
        String[] arr = {"aaa","b","ccc"};
        //输出排序前的数组
        arr.toString();
        //调用Arrays中的sort方法对字符串中的数组进行排序
        Arrays.sort(arr,getComparator());
        //输出排序后的数组
        System.out.println(Arrays.toString(arr));
    }
}

常用函数式接口

java.util.function包中提供了很多常用的函数式接口

Supplier接口

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

package com.lushuai.demo04.Supplier;
import java.util.function.Supplier;
public class Demo01Supplier {
    //定义一个方法,方法的参数传递Supplier<T>接口,泛型指定String,get方法就回返回一个String
    public static String getString (Supplier<String> sup) {
        return sup.get();
    }
    //调用getString方法,方法的参数Supplier是一个函数式接口,所以可以传递Lambda表达式
    public static void main(String[] args) {
        //生产一个字符串,并返回
        String s = getString(()->"小乔");
        System.out.println(s);
    }
}

实例:

/*
练习:求数组中的最大值
使用Supplier接口作为方法的参数类型,通过Lambda表达式求出int数组中的最大值
提示:接口的泛型请使用java.lang.Integer类。
 */
public class Demo02Test {
    //定义一个方法,用于获取int类型数组中元素的最大值,方法的参数传递Supplier接口,泛型使用Integer
    public static int getMax(Supplier<Integer> sup) {
        return sup.get();
    }
    public static void main(String[] args) {
        int[] arr = {1,5,9,41,-20,30,55};
        int maxValue = getMax(()->{
            int max = arr[0];
            for (int i = 0; i < arr.length; i++) {
                if (arr[i] > max){
                    max = arr[i];
                }
            }
            return max;
        });
        System.out.println("数组中的最大值是:"+maxValue);
    }
}
Consumer接口

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

public class Demo01Consumer {
 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));
        //消费方式二:反转输出
        /*method("王宝强",(name)->{
            String reName = new StringBuffer(name).reverse().toString();
            System.out.println(reName);
        });*/
    }
}
  • Consumer接口的默认方法andThen
    作用:需要两个Consumer接口,可以把两个Consumer接口组合到一起,再对数据进行消费
    例如:
    Consumer con1;
    Consumer con2;
    String s = “lushuai”;
    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);
        //使用andThen方法把两个Consumer接口连接到一起,再消费数据
        con1.andThen(con2).accept(s);
    }
    public static void main(String[] args) {
        method("lushuai",
                s -> System.out.println(s.toUpperCase()),//把字符串转换成大写输出
                s -> System.out.println(s.toLowerCase()));//把字符串转换成小写输出
    }
}
Predicate接口

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

public class Demo01Predicate {
    public static boolean checkString(String s , Predicate<String> pre) {
        return pre.test(s);
    }
    public static void main(String[] args) {
        String s = "abcde";
//        boolean b = checkString(s,(String str)->{
//           return s.length() > 5;
//        });
//        System.out.println(b);
        //优化lambda表达式
        boolean b = checkString(s, str-> s.length() > 5);
        System.out.println(b);
    }
}
  • Predicate接口中有一个方法and,表示并且关系,也可以用于连接两个判断条件
default Predicate<T> and (Predicate<? super T> other) {
        Object.requireNonNull(other);
        return (t) -> this.test(t) && other.test(t);
    }

方法内部的两个判断条件,也是使用&&运算符连接起来的。
代码示例:

/*
需求:判断一个字符串,有两个判断条件
    1、判断字符串的长度是否大于5
    2、判断字符串中是否包含a
    两个条件必须同时满足,可以使用&&运算符连接两个条件
*/
public class Demo02Predicate_and {
    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);
    }
    public static void main(String[] args) {
        String s = "bcdef";
        boolean b = checkString(s , str-> str.length()>5 , str-> str.contains("a"));
        System.out.println(b);
    }
}
  • Predicate接口中有一个方法or,表示或者关系,也可以用于连接两个判断条件
default Predicate<T> or (Predicate<? super T> other) {
        Object.requireNonNull(other);
        return (t) -> this.test(t) || other.test(t);
    }

方法内部的两个判断条件,也是使用||运算符连接起来的。
代码示例:

/*
需求:判断一个字符串,有两个判断条件
    1、判断字符串的长度是否大于5
    2、判断字符串中是否包含a
    满足一个条件即可,可以使用||运算符连接两个条件
*/
public class Demo03Predicate_or {
    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);
    }
    public static void main(String[] args) {
        String s = "bcdeff";
        boolean b = checkString(s , str-> str.length()>5 , str-> str.contains("a"));
        System.out.println(b);
    }
}
  • Predicate接口中有一个方法negate,表示取反的意思
default Predicate<T> negate() {
        return (t) -> !test(t);
    }

代码示例:

public class Demo04Predicate_negate {
    public static boolean checkString(String s, Predicate<String> pre) {
//        return !pre.test(s);
        return pre.negate().test(s);
    }
    public static void main(String[] args) {
        String s = "abc";
        boolean b = checkString(s, str -> str.length() > 5);
        System.out.println(b);
    }
}
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);
        int in = fun.apply(s);//自动拆箱  Integer-->int
        System.out.println(in);
    }
    public static void main(String[] args) {
        String s = "1234";
        change(s, str-> Integer.parseInt(str));
    }
}
  • Function接口中的默认方法andThen:用来进行组合操作
    例如:
    需求:
    把String类型的“123”转换为Integer类型,再把转换后的结果+10;再把增加之后的Integer类型的数据,转换为String类型
    分析:
    转换了两次
    1、把String类型转换为了Integer类型
    所以我们可以使用Function<String,Integer> fun1
    Integer i = fun1.apply(“123”)+10;
    2、把Integer类型转换为String类型
    所以我们可以使用Function<Integer,String> fun2
    String s = fun2.apply(i);
    我们可以使用andThen方法,把两次转换组合在一起使用
    String s = fun1.andThen(fun2).apply(“123”);
    fun1先调用apply方法,把字符串转换为Integer
    fun2再调用apply方法,把Integer转换为字符串
    代码示例:
public class Demo02Function_andThen {
    public static void change(String s, Function<String,Integer> fun1,Function<Integer,String> fun2) {
        String ss = fun1.andThen(fun2).apply(s);
        System.out.println(ss);
    }
    public static void main(String[] args) {
        String s = "1234";
//        change(s,(String str)->{
//            return Integer.parseInt(str)+10;
//        },(Integer i)->{
//            return i+" ";
//        });
        //优化Lambda表达式
        change(s,str->Integer.parseInt(str)+10,i->i+" ");
    }
}

以上就是几大常用函数式接口的简单介绍。

  • 2
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 1
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值