Java学习-函数式接口

1.函数式接口

1.1概述

函数式接口在Java中是指:有且仅有一个抽象方法的接口。 函数式接口,即适用于函数式编程场景的接口。而Java中的函数式编程体现就是Lambda,所以函数式接口就是可以适用于Lambda使用的接口。只有确保接口中有且仅有一个抽象方法,Java中的Lambda才能顺利地进行推导。

当然接口中可以包含其它的方法(默认,静态,私有)

1.2语法

只要确保接口中有且仅有一个抽象方法即可:

修饰符 interface 接口名称 {
	public abstract 返回值类型 方法名称(可选参数信息);
 	// 其他非抽象方法内容
 }

1.3@FunctionalInterface

当我们定义一个函数式接口的时候,我们可以使用注解 @FunctionalInterface 来注释

  • @FunctionalInterface: 检测是否是函数时接口
    • 如果接口有且只有一个抽象方法,编译成功
    • 当没有抽象方法,或则多余一个抽象方法的时候,会编译不通过
@FunctionalInterface
public interface MyFunctionInterface {
    public abstract void show();
}

2. 函数式编程

2.1Lambda的延迟执行

  • 性能浪费的日志案例
/*
    性能浪费日志案例:
    日志可以帮助我们快速定位问题,记录程序运行过程的情况,以便项目的监控和优化
    一种典型的场景就是对参数进行有条件的使用,例如对日志的消息凭借后,满足条件情况下打印日志

 */
public class FuncDemo {
    public static void main(String[] args) {
        String msgA = "Hello";
        String msgB = "World";
        String msgC = "Java";
        log(1, msgA + msgB + msgC);
        /*
        无论级别是否满足要求,作为 log 方法的第二个参数,三个字符串一定会首先被拼接并传入方
法内,然后才会进行级别判断。如果级别不符合要求,那么字符串的拼接操作就白做了,存在性能浪费。
         */


        //使用Lambda表达式实现性能的优化,当不满足条件的时候,字符串拼接操作是不会执行的
        log2(1, () -> msgA + msgB + msgC);
    }

    private static void log(int level, String msg) {
        if (level == 1) {
            System.out.println(msg);
        }
    }

    private static void log2(int level, MessageBuilder messageBuilder) {
        if (level == 1) {
            System.out.println(messageBuilder.buildMessage());
        }
    }

}

2.2 使用Lambda作为参数和返回值

Lambda作为参数
//首先定义一个函数式接口
@FunctionalInterface
public interface MyFunctionInterface {
    public abstract void show();
}
//定义一个方法
public static void showMethod(MyFunctionInterface myFunctionInterface){
        myFunctionInterface.show();
    }


//测试代码
//接口的作为参数的实现方式

        //1.直接传递实现接口的实现类
        showMethod(new MyFunctionInterfaceImpl());

        //2.使用匿名内部类的方式来实现
        showMethod(new MyFunctionInterface() {
            @Override
            public void show() {
                System.out.println("匿名内部类的方式来实现接口");
            }
        });

        //3.使用Lambda的方式来实现接口(只能函数式接口)
        showMethod(() -> {
            System.out.println("使用Lambda表达式来实现函数式接口");
        });

        //4.Lambda表达式的简化实现
        showMethod(() -> System.out.println("使用Lambda的简化方式来实现函数式接口"));
Lambda作为返回值
 /*
        定义一个使用Lambda表达式作为返回参数的方法
     */
    public static Comparator<String> customComparator() {
        //1.使用匿名内部类的方式来返回一个比较器
//        return new Comparator<String>() {
//            @Override
//            public int compare(String o1, String o2) {
//                return o1.length() - o2.length();
//            }
//        };

        //2.使用Lambda表示的方式返回
//        return (String o1, String o2) -> {
//            return o1.length() - o2.length();
//        };

        //3.使用Lambda的简化方式
        return (String o1, String o2) -> o1.length() - o2.length();
    }

//Lambda表达式作为返回值的测试
        String[] temp = {"aaaa","b","cccccccc","dddddddddd"};
        System.out.println("没有排序前的字符串数组=====" + Arrays.toString(temp
        ));
        Arrays.sort(temp, customComparator());
        System.out.println("排序后的字符串数组=======" + Arrays.toString(temp
        ));

3.Java常用函数式接口

JDK提供了大量常用的函数式接口以丰富Lambda的典型使用场景,它们主要在 java.util.function 包中被提供。 下面是最简单的几个接口及使用示例。

3.1 Supplier接口

java.util.function.Supplier 接口仅包含一个无参的方法: T get() 。用来获取一个泛型参数指定类型的对 象数据。由于这是一个函数式接口,这也就意味着对应的Lambda表达式需要“对外提供”一个符合泛型类型的对象 数据。

  • 代码示例:
public class SupplierDemo {

    public static void main(String[] args) {
        //测试Supplier的简单用法
        supplierTest();
        supplierExample();
    }

    /*
        求数组中元素的最大值
     */
    public static void supplierExample(){
        int[] arr = {100,80,120,60};
        int maxCount = getMax(arr, () ->{
            int max = arr[0];
            for (int i = 1; i < arr.length-1; i++) {
                if (max > arr[i]) {
                    max = arr[i];
                }
            }

            return max;
        });
    }

    public static int getMax(int[] arr, Supplier<Integer> supplier) {
        return supplier.get();
    }

    /*
        supplier 的简单运用代码
     */
    public static void supplierTest() {
        /*
            Supplier: java.util.function.Supplier<T> 接口仅包含一个无参的方法: T get()
            用来获取一个泛型参数指定类型的对 象数据,生产数据
         */
        //简单使用-> 使用匿名内部类的方式
        int count = getCount(new Supplier<Integer>() {
            @Override
            public Integer get() {
                return 20;
            }
        });
        System.out.println("count======" + count);

        //使用Lambda表达式来使用
        int count2 = getCount(() -> {
            return  30;
        });
        System.out.println("Lambda表达式====" + count2);

        //优化
        int count3 = getCount(() -> 60);
        System.out.println("优化后lambda表达式======" + count3);
    }

    /*
        使用Supplier接口生产一个Int类型的数据
     */
    public static int getCount(Supplier<Integer> supplier) {
        return  supplier.get();
    }

}

3.2 Consumer接口

java.util.function.Consumer 接口则正好与Supplier接口相反,它不是生产一个数据,而是消费一个数据, 其数据类型由泛型决定。

  • 代码示例
public class ConsumerDemo {
    public static void main(String[] args) {
        //1.Consumer:接口与Supplier接口正好相反 是消费数据
        consumerTest("我爱Java", new Consumer<String>() {
            @Override
            public void accept(String s) {
                System.out.println("匿名内部类实现====" + s);
            }
        });

        consumerTest("我爱Java",(String s) -> {
            System.out.println("Lambda表达式=====" + s);
        });

        //优化
        consumerTest("我爱Java",s -> System.out.println("Lambda表达式优化之后=====" + s));

        //Consumer中的默认方法测试 andThen() 方式
        consumerTest2("我爱Java",(String s) -> {
            System.out.println("andThen first====" + s);
        },(String s) -> {
            System.out.println("andThen seconde=====" + s);
        });
    }

    public static void consumerTest(String testString, Consumer<String> consumer) {
        consumer.accept(testString);
    }

    public static void consumerTest2(String testString, Consumer<String> consumer, Consumer<String> consumer2) {
        consumer.andThen(consumer2).accept(testString);
    }
}

3.3 Predicate接口

有时候我们需要对某种类型的数据进行判断,从而得到一个boolean值结果。这时可以使用
java.util.function.Predicate 接口。

*代码案例:

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

        //测试判断字符串中包含不包含a
        String str = "dsadsad";
        boolean b = predicateTest(str, s -> {
           return s.contains("a");
        });
        System.out.println(b);

        //判断字符串里面是否同时包含s 还包含b  and方法
        boolean b1 = predicateTest2(str, s -> s.contains("s"), s -> s.contains("b"));
        System.out.println(b1);

        //使用or方法来判断
        boolean b2 = predicateTest2(str, s -> s.contains("s"), s -> s.contains("d"));
        System.out.println(b2);

        //negate() 非的结果 结果取反
        boolean b3 = predicateTest(str, s -> s.contains("x"));
        System.out.println(b3);
    }

    public static boolean predicateTest(String testString, Predicate<String> predicate) {
       return predicate.test(testString);
    }

    public static boolean predicateTest2(String testString, Predicate<String> predicate, Predicate<String> predicate2) {
        return predicate.and(predicate2).test(testString);
    }

    public static boolean predicateTest3(String testString, Predicate<String> predicate, Predicate<String> predicate2) {
        return predicate.or(predicate2).test(testString);
    }

}

3.4 Function接口

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

  • 代码案例:
public class FunctionDemo {
    public static void main(String[] args) {

        int count = functionTest("123", s -> Integer.parseInt(s));
        System.out.println("count======" + count);

        //anThen的方法连续转转 谁在前  谁先转换 第一步转换完成之后s编程Integer类型 , 在接着把Integer转换成String类型
        String str = functionTest2("123",s -> Integer.parseInt(s), s -> String.valueOf(count));
        System.out.println("str====== " + str);
    }

    /*
        Function<String, Integer>: 把String类型的数据转换成为Integer类型的数据 apply()方法
     */
    public static int functionTest(String testString, Function<String, Integer> function) {
        return function.apply(testString);
    }

    public static String functionTest2(String testString, Function<String, Integer> function, Function<Integer, String> function2) {
        return function.andThen(function2).apply(testString);
    }

}

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值