zoukankan      html  css  js  c++  java
  • java8 函数式接口——Function/Predict/Supplier/Consumer

    Function

    我们知道Java8的最大特性就是函数式接口。所有标注了@FunctionalInterface注解的接口都是函数式接口,具体来说,所有标注了该注解的接口都将能用在lambda表达式上。

    接口介绍

    /**
     * Represents a function that accepts one argument and produces a result.
     *
     * <p>This is a <a href="package-summary.html">functional interface</a>
     * whose functional method is {@link #apply(Object)}.
     *
     * @param <T> the type of the input to the function
     * @param <R> the type of the result of the function
     *
     * @since 1.8
     */
    

    上述描述可知: Function中传递的两个泛型:T,R分别代表 输入参数类型和返回参数类型。下面将逐个介绍Function中的各个接口:

    接口1: 执行具体内容接口
    R apply(T t);

    实例1:apply使用
        // 匿名类的方式实现
        Function<Integer, Integer> version1 = new Function<Integer, Integer>() {
            @Override
            public Integer apply(Integer integer) {
                return integer++;
            }
        };
        int result1 = version1.apply(20);
    
    
        // lamda表达式
        Function<Integer, Integer> version2 = integer -> integer++;
        int result2 = version1.apply(20);
    

    接口2: compose
    该方法是一个默认方法,这个方法接收一个function作为参数,将参数function执行的结果作为参数给调用的function,以此来实现两个function组合的功能。

    // compose 方法源码
    default <V> Function<V, R> compose(Function<? super V, ? extends T> before) {
            Objects.requireNonNull(before);
            return (V v) -> apply(before.apply(v));
        }
    
    
    实例2:compose使用
    public int compute(int a, Function<Integer, Integer> function1, Function<Integer, Integer> function2) {
        return function1.compose(function2).apply(a);
    }
    
    // 调用上述方法
    test.compute(2, value -> value * 3, value -> value * value) 
    // 执行结果: 12 (有源码可以看出先执行before)
    

    接口3 : andThen
    了解了compose方法,我们再来看andThen方法就好理解了,听名字就是“接下来”,andThen方法也是接收一个function作为参数,与compse不同的是,先执行本身的apply方法,将执行的结果作为参数给参数中的function。

    public interface Function<T, R> {
        default <V> Function<T, V> andThen(Function<? super R, ? extends V> after) {
            Objects.requireNonNull(after);
            return (T t) -> after.apply(apply(t));
        }
    }
    
    实例3:andThen使用
    public int compute2(int a, Function<Integer, Integer> function1, Function<Integer, Integer> function2) {
        return function1.andThen(function2).apply(a);
    }
    
    // 调用上述方法
    test.compute2(2, value -> value * 3, value -> value * value) 
    // 执行结果 : 36
    

    反思: 多个参数

    Function接口虽然很简洁,但是由Function源码可以看出,他只能传一个参数,实际使用中肯定不能满足需求。下面提供几种思路:

    1. BiFunction可以传递两个参数(Java8中还提供了其它相似Function)
    2. 通过封装类来解决
    3. void函数还是无法解决

    因为参数原因“自带的Function”函数必然不能满足业务上复杂多变的需求,那么就自定义Function接口吧

    @FunctionalInterface
        static interface ThiConsumer<T,U,W>{
            void accept(T t, U u, W w);
    
            default ThiConsumer<T,U,W> andThen(ThiConsumer<? super T,? super U,? super W> consumer){
                return (t, u, w)->{
                    accept(t, u, w);
                    consumer.accept(t, u, w);
                };
            }
        }
    

    自此,Function接口介绍完毕。

    断言性接口:Predicate

    接口介绍:

    /**
     * Represents a predicate (boolean-valued function) of one argument.
     *
     * <p>This is a <a href="package-summary.html">functional interface</a>
     * whose functional method is {@link #test(Object)}.
     *
     * @param <T> the type of the input to the predicate
     *
     * @since 1.8
     */
    @FunctionalInterface
    public interface Predicate<T> {
    

    Predicate是个断言式接口其参数是<T,boolean>,也就是给一个参数T,返回boolean类型的结果。跟Function一样,Predicate的具体实现也是根据传入的lambda表达式来决定的。

    源码不再具体分析,主要有 test/and/or/negate方法,以及一个静态方法isEqual,具体使用实例如下:

        private static void testPredict() {
            int[] numbers = {1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15};
            List<Integer> list = new ArrayList<>();
            for (int i : numbers) {
                list.add(i);
            }
            
            // 三个判断
            Predicate<Integer> p1 = i -> i > 5;
            Predicate<Integer> p2 = i -> i < 20;
            Predicate<Integer> p3 = i -> i % 2 == 0;
            List test = list.stream()
                    .filter(p1
                            .and(p2)
    //                        .and(Predicate.isEqual(8))
                            .and(p3))
                    .collect(Collectors.toList());
            System.out.println(test.toString());
            //print:[6, 8, 10, 12, 14]
        }
    
    

    供给性接口:Supplier

    接口介绍

    /**
     * Represents a supplier of results.
     *
     * <p>There is no requirement that a new or distinct result be returned each
     * time the supplier is invoked.
     *
     * <p>This is a <a href="package-summary.html">functional interface</a>
     * whose functional method is {@link #get()}.
     *
     * @param <T> the type of results supplied by this supplier
     *
     * @since 1.8
     */
    @FunctionalInterface
    public interface Supplier<T> 
    

    使用实例:

            Supplier supplier = "Hello"::toLowerCase;
            System.out.println(supplier);
    

    消费性:Consumer

    接口介绍

    /**
     * Represents an operation that accepts a single input argument and returns no
     * result. Unlike most other functional interfaces, {@code Consumer} is expected
     * to operate via side-effects.
     *
     * <p>This is a <a href="package-summary.html">functional interface</a>
     * whose functional method is {@link #accept(Object)}.
     *
     * @param <T> the type of the input to the operation
     *
     * @since 1.8
     */
    @FunctionalInterface
    public interface Consumer<T> {
    

    实际使用

        NameInfo info = new NameInfo("abc", 123);
        Consumer<NameInfo> consumer = t -> {
            String infoString = t.name + t.age;
            System.out.println("consumer process:" + infoString);
        };
        consumer.accept(info);
    

    总结:
    本文主要介绍Java8的接口式编程,以及jdk中提供的四种函数接口(FunctionalInterface)。Predict/Supplier/Consumer其实是Function的一种变形,所以没有详细介绍。
    疑问: FunctionalInterface注解是如何和lamada表达式联系在一起,函数接口在编译时又是如何处理的?后面再了解下

  • 相关阅读:
    一道编程题: 在1~n之间选择若干个数,使其和为m
    关于raft算法
    程序员算法基础——动态规划
    c++中两个类互相引用的问题
    c++ 之模板进阶
    jmeter分布式操作-远程启动功能探索
    linux下安装不同版本的jdk
    Jmeter插件监控服务器性能
    测试开发面试-技术持续累积
    python:Jpype安装和使用
  • 原文地址:https://www.cnblogs.com/NeilZhang/p/11086698.html
Copyright © 2011-2022 走看看