zoukankan      html  css  js  c++  java
  • JAVA8学习——深入浅出函数式接口FunctionInterface(学习过程)

    函数式接口

    函数式接口详解:FunctionInterface接口

    话不多说,先打开源码,查阅一番。寻得FunctionInterface接口

    package java.util.function;
    
    import java.util.Objects;
    
    /**
     * 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
     */
    @FunctionalInterface
    public interface Function<T, R> {
    
        /**
         * Applies this function to the given argument.
         *
         * @param t the function argument
         * @return the function result
         */
        R apply(T t);
    
        /**
         * Returns a composed function that first applies the {@code before}
         * function to its input, and then applies this function to the result.
         * If evaluation of either function throws an exception, it is relayed to
         * the caller of the composed function.
         *
         * @param <V> the type of input to the {@code before} function, and to the
         *           composed function
         * @param before the function to apply before this function is applied
         * @return a composed function that first applies the {@code before}
         * function and then applies this function
         * @throws NullPointerException if before is null
         *
         * @see #andThen(Function)
         */
        default <V> Function<V, R> compose(Function<? super V, ? extends T> before) {
            Objects.requireNonNull(before);
            return (V v) -> apply(before.apply(v));
        }
    
        /**
         * Returns a composed function that first applies this function to
         * its input, and then applies the {@code after} function to the result.
         * If evaluation of either function throws an exception, it is relayed to
         * the caller of the composed function.
         *
         * @param <V> the type of output of the {@code after} function, and of the
         *           composed function
         * @param after the function to apply after this function is applied
         * @return a composed function that first applies this function and then
         * applies the {@code after} function
         * @throws NullPointerException if after is null
         *
         * @see #compose(Function)
         */
        default <V> Function<T, V> andThen(Function<? super R, ? extends V> after) {
            Objects.requireNonNull(after);
            return (T t) -> after.apply(apply(t));
        }
    
        /**
         * Returns a function that always returns its input argument.
         *
         * @param <T> the type of the input and output objects to the function
         * @return a function that always returns its input argument
         */
        static <T> Function<T, T> identity() {
            return t -> t;
        }
    }
    
    

    函数式接口代码测试:FunctionTest

    public class FunctionTest {
        public static void main(String[] args) {
            FunctionTest test = new FunctionTest();
            // 传递行为,而不是传递值
            System.out.println(test.comput(1, value -> 2 * value));
    
            System.out.println(test.comput(2, value -> 5 + value));
    
            System.out.println(test.comput(3,Integer::intValue));
    
            System.out.println(test.convert(4,value -> value + "helloworld"));
        }
    
        public int comput(int a, Function<Integer, Integer> function) {
            //apply ,传递的是行为
            int result = function.apply(a);
            return result;
        }
    
        public String convert(int a, Function<Integer, String> function) {
            return function.apply(a);
        }
    
        //    对于之前只传递值的写法,几种行为就要定义几种写法。 现在可以使用上面的方式去 传递行为
        public int method1(int a) {
            return a + 1;
        }
    
        public int method2(int a) {
            return a * 5;
        }
    
        public int method3(int a) {
            return a * a;
        }
    }
    

    高阶函数:如果一个函数接收一个函数作为参数,或者返回一个函数作为返回值,那么该函数就叫做高阶函数。函数式编程语言js等语言里面都支持大量的高阶函数,JAVA从1.8开始也开始支持高阶函数。

    FunctionInterface接口中提供的方法详解

    1. apply
    2. compose (function组合)
    3. andThen
    4. identity

    代码测试上述方法

    package java.util.function;
    
    import java.util.Objects;
    
    /**
     * 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
     */
    @FunctionalInterface
    public interface Function<T, R> {
    
        /**
         * Applies this function to the given argument.
         *
         * @param t the function argument
         * @return the function result
         */
        R apply(T t);
    
        /**
         * Returns a composed function that first applies the {@code before}
         * function to its input, and then applies this function to the result.
         * If evaluation of either function throws an exception, it is relayed to
         * the caller of the composed function.
         *
         * @param <V> the type of input to the {@code before} function, and to the
         *           composed function
         * @param before the function to apply before this function is applied
         * @return a composed function that first applies the {@code before}
         * function and then applies this function
         * @throws NullPointerException if before is null
         
         * 先应用beforefunction,再应用实例的function
         实际上:将两个function组合在一起了。先执行before方法,然后将处理的结果传递给当前对象的apply方法。实现了两个function的串联。既然实现了两个function的串联,就能实现多个函数的串联。
         * @see #andThen(Function)
         */
        default <V> Function<V, R> compose(Function<? super V, ? extends T> before) {
            Objects.requireNonNull(before);
            return (V v) -> apply(before.apply(v));
        }
    
        /**
         * Returns a composed function that first applies this function to
         * its input, and then applies the {@code after} function to the result.
         * If evaluation of either function throws an exception, it is relayed to
         * the caller of the composed function.
         *
         * @param <V> the type of output of the {@code after} function, and of the
         *           composed function
         * @param after the function to apply after this function is applied
         * @return a composed function that first applies this function and then
         * applies the {@code after} function
         * @throws NullPointerException if after is null
         
         和before函数相反,先应用this function,然后再使用after方法。 实现两个方法的串联。
         
         * @see #compose(Function)
         */
        default <V> Function<T, V> andThen(Function<? super R, ? extends V> after) {
            Objects.requireNonNull(after);
            return (T t) -> after.apply(apply(t));
        }
    
        /**
         * Returns a function that always returns its input argument.
         *
         * @param <T> the type of the input and output objects to the function
         * @return a function that always returns its input argument
         */
        static <T> Function<T, T> identity() {
            return t -> t;
        }
    }
    
    • compose:
      先应用beforefunction,再应用实例的function
      实际上:将两个function组合在一起了。先执行before方法,然后将处理的结果传递给当前对象的apply方法。实现了两个function的串联。既然实现了两个function的串联,就能实现多个函数的串联。
    • andThen:
      和before函数相反,先应用this function,然后再使用after方法。 实现两个方法的串联。
    • identity:
      传入什么,返回什么。

    这些方法都是很有价值的。

    /**
     *  compose , andThen 方法的使用
     */
    public class FunctionTest2 {
    
        public static void main(String[] args) {
            FunctionTest2 test2 = new FunctionTest2();
            int compute = test2.compute(2, v -> v * 3, v -> v * v);//12
            int compute2 = test2.compute2(2, v -> v * 3, v -> v * v);//36
            System.out.println(compute);
            System.out.println(compute2);
        }
    
        public int compute(int a, Function<Integer, Integer> function1, Function<Integer, Integer> function2) {
            return function1.compose(function2).apply(a);
        }
        public int compute2(int a, Function<Integer, Integer> function1, Function<Integer, Integer> function2) {
            return function1.andThen(function2).apply(a);
        }
    }
    

    BiFunction类详解

    package java.util.function;
    
    import java.util.Objects;
    
    /**
     * Represents a function that accepts two arguments and produces a result.
     * This is the two-arity specialization of {@link Function}.
     *
     * <p>This is a <a href="package-summary.html">functional interface</a>
     * whose functional method is {@link #apply(Object, Object)}.
     *
     * @param <T> the type of the first argument to the function
     * @param <U> the type of the second argument to the function
     * @param <R> the type of the result of the function
     *
     * @see Function
     * @since 1.8
     */
    @FunctionalInterface
    public interface BiFunction<T, U, R> {
    
        /**
         * Applies this function to the given arguments.
         *
         * @param t the first function argument
         * @param u the second function argument
         * @return the function result
         */
        R apply(T t, U u);
    
        /**
         * Returns a composed function that first applies this function to
         * its input, and then applies the {@code after} function to the result.
         * If evaluation of either function throws an exception, it is relayed to
         * the caller of the composed function.
         *
         * @param <V> the type of output of the {@code after} function, and of the
         *           composed function
         * @param after the function to apply after this function is applied
         * @return a composed function that first applies this function and then
         * applies the {@code after} function
         * @throws NullPointerException if after is null
         */
        default <V> BiFunction<T, U, V> andThen(Function<? super R, ? extends V> after) {
            Objects.requireNonNull(after);
            return (T t, U u) -> after.apply(apply(t, u));
        }
    }
    
    

    BiFunction类,双向接口类,提供了两个输入参数,一个输出参数

        //BiFunction类的使用。 有两个输入参数
        public int compute3(int a, int b, BiFunction<Integer, Integer, Integer> biFunction) {
            return biFunction.apply(a, b);
        }
    
        public int compute4(int a, int b, BiFunction<Integer, Integer, Integer> biFunction,Function<Integer,Integer> function) {
            return biFunction.andThen(function).apply(a,b);
        }
        
        //使用BiFunction来完成
        System.out.println(test2.compute3(1,2,(value1,value2)-> value1 + value2));
        System.out.println(test2.compute3(1,2,(value1,value2)-> value1 - value2));
        System.out.println(test2.compute3(1, 2, (value1, value2) -> value1 * value2));
        System.out.println(test2.compute3(1, 2, (value1, value2) -> value1 / value2));
            
        //使用BiFunction中的andThen.
        System.out.println(test2.compute4(2,3,(value1,value2)->value1+value2,value->value*value));
    

    为什么BiFunction类中没有Compose方法呢?

    倒推一下:因为如果有Compose方法,会先执行参数的Function。无论参数是Function还是BiFunction,返回值也都是一个值,然后就没办法再去执行BiFuntion.


    使用lambda表达式解决简单的开发问题:

    定义一个简单的Person类,然后使用lambda表达式解决一些问题
    public class Person {
        private String username;
        private int age;
    }
    
    package com.dawa.jdk8;
    
    import java.util.Arrays;
    import java.util.List;
    import java.util.function.BiFunction;
    import java.util.stream.Collectors;
    
    public class PersonTest {
        public static void main(String[] args) {
    
            Person person1 = new Person("zhangsan", 20);
            Person person2 = new Person("lisi", 30);
            Person person3 = new Person("wangwu", 40);
    
            List<Person> list = Arrays.asList(person1,person2,person3);
    
            PersonTest test = new PersonTest();
            //测试第一个方法。
            List<Person> list1 = test.getPersonByUsername("zhangsan", list);
            list1.forEach(person -> System.out.println(person.getUsername()));
            //测试第二种方法
            List<Person> personByAge = test.getPersonByAge(20, list);
            personByAge.forEach(person -> System.out.println(person.getAge()));
            //测试第三方法
            List<Person> peopleList = test.getPersonByArg(20, list,
                    (age, personList) -> personList.stream().filter(p
                    erson -> person.getAge() > age).collect(Collectors.toList()));
            peopleList.forEach(person -> System.out.println(person.getUsername()));
    
        }
    
        //使用lambda表达式定义一个 处理的方法
        //filter 方法,参数是一个Predicate 谓语
        //stream 提供了一个将流转换成集合的方法 collect(Collectors.toList())
        public List<Person> getPersonByUsername(String username, List<Person> personList) {
            return personList.stream().
            filter(person -> 
            person.getUsername().equals("zhangsan")).collect(Collectors.toList());
        }
    
        //第二种方式,先直接使用lambda表达式将BiFunction定义好,然后直接将方法的两个参数传入到BiFunction.
        public List<Person> getPersonByAge(int age, List<Person> personList) {
            BiFunction<Integer, List<Person>, List<Person>> biFunction = (ageArg, Persons) -> {
              return   Persons.stream().filter(person -> person.getAge() > ageArg).collect(Collectors.toList());
            };
            return biFunction.apply(age,personList);
        }
        
        //第三种方式,动作也让他自己传递。 函数式接口的好处。
        public List<Person> getPersonByArg(int age, List<Person> personList, BiFunction<Integer, List<Person>, List<Person>> biFunction) {
            return biFunction.apply(age, personList);
        }
    }
    

    真谛:函数式接口,传递的是行为,而不是数据。

    Predicate 类详解(谓词)

    package java.util.function;
    
    import java.util.Objects;
    
    /**
     * 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> {
    
        /**
         * Evaluates this predicate on the given argument.
         *
         * @param t the input argument
         * @return {@code true} if the input argument matches the predicate,
         * otherwise {@code false}
         */
        boolean test(T t);
    
        /**
         * Returns a composed predicate that represents a short-circuiting logical
         * AND of this predicate and another.  When evaluating the composed
         * predicate, if this predicate is {@code false}, then the {@code other}
         * predicate is not evaluated.
         *
         * <p>Any exceptions thrown during evaluation of either predicate are relayed
         * to the caller; if evaluation of this predicate throws an exception, the
         * {@code other} predicate will not be evaluated.
         *
         * @param other a predicate that will be logically-ANDed with this
         *              predicate
         * @return a composed predicate that represents the short-circuiting logical
         * AND of this predicate and the {@code other} predicate
         * @throws NullPointerException if other is null
         */
        default Predicate<T> and(Predicate<? super T> other) {
            Objects.requireNonNull(other);
            return (t) -> test(t) && other.test(t);
        }
    
        /**
         * Returns a predicate that represents the logical negation of this
         * predicate.
         *
         * @return a predicate that represents the logical negation of this
         * predicate
         */
        default Predicate<T> negate() {
            return (t) -> !test(t);
        }
    
        /**
         * Returns a composed predicate that represents a short-circuiting logical
         * OR of this predicate and another.  When evaluating the composed
         * predicate, if this predicate is {@code true}, then the {@code other}
         * predicate is not evaluated.
         *
         * <p>Any exceptions thrown during evaluation of either predicate are relayed
         * to the caller; if evaluation of this predicate throws an exception, the
         * {@code other} predicate will not be evaluated.
         *
         * @param other a predicate that will be logically-ORed with this
         *              predicate
         * @return a composed predicate that represents the short-circuiting logical
         * OR of this predicate and the {@code other} predicate
         * @throws NullPointerException if other is null
         */
        default Predicate<T> or(Predicate<? super T> other) {
            Objects.requireNonNull(other);
            return (t) -> test(t) || other.test(t);
        }
    
        /**
         * Returns a predicate that tests if two arguments are equal according
         * to {@link Objects#equals(Object, Object)}.
         *
         * @param <T> the type of arguments to the predicate
         * @param targetRef the object reference with which to compare for equality,
         *               which may be {@code null}
         * @return a predicate that tests if two arguments are equal according
         * to {@link Objects#equals(Object, Object)}
         */
        static <T> Predicate<T> isEqual(Object targetRef) {
            return (null == targetRef)
                    ? Objects::isNull
                    : object -> targetRef.equals(object);
        }
    }
    

    默认调用:boolean test(T t)给定一个输入参数,判断是否满足条件。满足则返回true,不满足返回false。

    测试案例:

    package com.dawa.jdk8;
    
    import java.util.function.Predicate;
    
    public class PreDicateTest {
        public static void main(String[] args) {
            Predicate<String> predicate = p -> p.length() > 5;
    
            System.out.println(predicate.test("hello"));
    
        }
    }
    

    这个接口会在流stream里面得到大量的运用。上述案例在 stream的 filter()方法参数中使用。

    到现在为止,Function包下的接口已经基础了两个了。
    可是只是讲了几个特别重要的接口,其他的接口是没时间一个一个讲的。

    这个时候我去看了一下源码,发现JAVA8底层源码,大量的使用函数接口来进行实现。

    道阻且长。~ 加油。
    2019年12月29日22:18:25。明天就要上班了,今晚早点休息。

  • 相关阅读:
    HTML5学习笔记简明版(1):HTML5介绍与语法
    用margin还是用padding(1)——W3School CSS外边距合并
    Minimum Depth of Binary Tree
    118. Pascal's Triangle
    Convert Sorted Array to Binary Search Tree
    112. Path Sum
    Balanced Binary Tree
    centos 7下nginx搭建流媒体服务器【动态添加模块】
    Java内存泄漏
    Quartz的job中注入的services接口为空的解决办法
  • 原文地址:https://www.cnblogs.com/bigbaby/p/12116886.html
Copyright © 2011-2022 走看看