• java代码(15) ---java8 Function 、Consumer 、Supplier



    Java8 Function、Consumer、Supplier


    有关JDK8新特性之前还有三篇博客:

    1,java代码(1)---Java8 Lambda 

    2,java代码(2)---Java8 Stream 

    3,java代码(3)---Predicate详解

    这一篇我们来了解JDK8已经定义好的几个函数式接口

    一、概述

    jdk8之后新增的一个重要的包,java,util.function

    该包下所有的接口都是函数式接口,按分类主要分为四大接口类型:Function、Consumer、Predicate、Supplier ,有关Predicate这里不再讲解

     java.util.Function包如下

     二、Consumer

    作用,一听这个名字就知道是消费某个对象,没有返回值

    1、源码

    @FunctionalInterface
    public interface Consumer<T> {
    
        /**
         * 抽象方法:传入一个指定泛型的参数,无返回值
         */
        void accept(T t);
    
        /**
         * 如同方法名字一样andThen,类似一种相加的功能(下面会举例说明)
         */
        default Consumer<T> andThen(Consumer<? super T> after) {
            Objects.requireNonNull(after);
            return (T t) -> { accept(t); after.accept(t); };
        }
    }

    2、使用示例

     public static void main(String[] args) {
            testConsumer();
            testAndThen();
        }
    
        /**
         * 一个简单的平方计算
         */
        private static void testConsumer() {
            //设置好consumer实现方法
            Consumer<Integer> square=x-> System.out.println("平方计算:"+x*x);
            square.accept(2);
        }
    
        /**
         * 定义3个consumer并按顺序进行调研andThen方法
         */
        private static void testAndThen() {
            //当前值
            Consumer<Integer> consumer1=x-> System.out.println("当前值:"+x);
            //相加
            Consumer<Integer> consumer2=x-> System.out.println("相加:"+(x+x));
            //相乘
            Consumer<Integer> consumer3=x-> System.out.println("相乘:"+x*x);
            //andThen拼接
            consumer1.andThen(consumer2).andThen(consumer3).accept(1);
        }

    运行结果:

     单这样消费看去并没啥意义,但如果是集合操作就有意义了,所以jdk8的Iterator接口就引入了Consumer

    3、JDK8使用

    Iterable接口的forEach方法需要传入Consumer,大部分集合类都实现了该接口,用于返回Iterator对象进行迭代

    public interface Iterable<T> {
        //forEach方法传入的就是Consumer
        default void forEach(Consumer<? super T> action) {
            Objects.requireNonNull(action);
            for (T t : this) {
                action.accept(t);
            }
        }
    }

    我们在来看带来的便利

      public static void main(String[] args) {
            //1有个集合,集合里的对象有age
            List<Student> studentList=new ArrayList<>();
            for (Student student : studentList) {
                student.setAge(1);
            }
            //2、通过forEach的Consumer添加
            studentList.forEach(x->x.setAge(1));
        }

    这样一比较代码确实简洁了点,这就是Consumer给我们写代码带来简洁的地方

    三、Supplier

    作用:提前定义可能返回的一个指定类型结果,等调用的时候在获取结果

    1、源码

    @FunctionalInterface
    public interface Supplier<T> {
    
        /**
         * 只有这一个抽象类
         */
        T get();
    }

    源码非常简单

    2、JDK8使用

    在JDK8中Optional对象有使用到

        Optional.orElseGet(Supplier<? extends T>)//当对象为null,就通过传入supplier创建一个返回

    我们看下源码:

     public <X extends Throwable> T orElseThrow(Supplier<? extends X> exceptionSupplier) throws X {
            if (value != null) {
                return value;
            } else {
                throw exceptionSupplier.get();
            }
        }

    使用示例

     public static void main(String[] args) {
            Person son = null;
            //先判断son是否为null,如果为不为null则返回当前对象,如果为null则返回新创建的对象
            BrandDTO optional = Optional.ofNullable(son).orElseGet(() -> new Person());
    
        }

    这样代码是不是又简单了。有关Optional下面会写一篇博客

    四、Function

    作用,实现一个“一元函数”,即传入一个值经过函数的计算返回另外一个值

     @FunctionalInterface
        public interface Function<T, R> {
            
            /**
             * 抽象方法: 根据一个数据类型T加工得到一个数据类型R
             */
            R apply(T t);
    
            /**
             * 组合函数,调用当前function之前调用
             */
            default <V> java.util.function.Function<V, R> compose(java.util.function.Function<? super V, ? extends T> before) {
                Objects.requireNonNull(before);
                return (V v) -> apply(before.apply(v));
            }
    
            /**
             * 组合函数,调用当前function之后调用
             */
            default <V> java.util.function.Function<T, V> andThen(java.util.function.Function<? super R, ? extends V> after) {
                Objects.requireNonNull(after);
                return (T t) -> after.apply(apply(t));
            }
    
            /**
             *  静态方法,返回与原函数参数一致的结果。x=y
             */
            static <T> java.util.function.Function<T, T> identity() {
                return t -> t;
            }
        }

    使用示例

     public static void main(String[] args) {
            applyTest();
            andThenTest();
            composeTest();
             test();
        }
    
        /**
         * 1、apply示例
         */
        private static void applyTest() {
            //示例一:
            Function<String,Integer> function=x->Integer.parseInt(x);
            Integer a=function.apply("100");
            System.out.println(a.getClass());
            //结果:class java.lang.Integer
        }
    
        /**
         * 2、andThen示例
         */
        private static void andThenTest() {
            //示例2:使用andThen()实现一个函数 y=10x+10;
            //先执行 10*x
            Function<Integer,Integer> function=x->10*x;
            //通过andThen在执行,这里的x就等于上面的10*x的值
            function=function.andThen(x->x+10);
            System.out.println(function.apply(2));
            //结果:30
        }
        /**
         * 3、compose示例
         */
        private static void composeTest() {
            //示例3:使用compose()实现一个函数y=(10+x)2;
            Function<Integer,Integer> function=x->x*2;
            //先执行x+10在执行(x+10)*2顺序与上面相反
            function=function.compose(x->x+10);
            System.out.println(function.apply(3));
            //结果:26
        }
        /**
         *  4、总和示例
         */
    
        private static void test() {
            //示例4:使用compose()、andThen()实现一个函数 y=(10+x)*2+10;
            //执行第二步
            Function<Integer,Integer> function=x->x*2;
            //执行第一步
            function=function.compose(x->x+10);
            //执行第三步
            function=function.andThen(x->x+10);
            System.out.println(function.apply(3));
            //结果:36
        }

    3、JDK8使用

    有两个地方很常用

    1、V HashMap.computeIfAbsent(R,Function<K,V>) //简化代码,如果指定的键尚未与值关联或与null关联,使用函数返回值替换
    2、<R>Stream<R> map(Function<?super T,? extends R> mapper);//转换流

    computeIfAbsent使用示例

     public static void main(String[] args) {
            Map<String, List<String>> map = new HashMap<>();
            List<String> list;
            //java8之前的写法
            list = map.get("key");
            if (list==null){
                list=new LinkedList<>();
                map.put("key",list);
            }
            list.add("11");
    
            //使用computeIfAbsent可以这样写,如果key返回不为空,则返回该集合,为空则创建集合返回
            list=map.computeIfAbsent("key",k->new ArrayList<>());
            list.add("11");
        }

    stream中map使用示例

     public static void main(String[] args) {
            List<Person> persionList = new ArrayList<Person>();
            persionList.add(new Person("张三",28,"女"));
            persionList.add(new Person("小小",2,"女"));
            persionList.add(new Person("李四",65,"男"));
    
            //只取出该集合中所有姓名组成一个新集合(将person对象转为string对象)
            List<String> nameList=persionList.stream().map(Person::getName).collect(Collectors.toList());
            System.out.println(nameList.toString());
            //输出结果:[张三, 小小, 李四]
        }

    代码看上去又整洁了

    总结:这些函数式接口作用在我看来,就是定义一个方法,方法中有个参数是函数式接口,这样的话函数的具体实现则由调用者来实现,这就是函数式接口的意义所在

    一般我们也会很少去定义一个方法,方法参数包含函数接口,我们更重要的是学会使用JDK8中带有函数式接口参数的方法,来简化我们的代码

  • 相关阅读:
    element-ui 和ivew-ui的table导出export纯前端(可用)
    webstrom 2019 注册码(可用 2019年10月14日08:59:18)
    intellji IDEA 2019版激活码(亲测可用 2019年10月14日08:53:54)
    java开发相关工具安装包分享
    js有关字符串拼接问题
    js增删class的方法
    有关定位问题
    关于网页元素居中常见的两种方法
    有关css编写文字动态下划线
    js获取时间及转化
  • 原文地址:https://www.cnblogs.com/zhenbian/p/13032427.html
Copyright © 2020-2023  润新知