java代码之美(15)---Java8 Function、Consumer、Supplier

Java8 Function、Consumer、Supplier

有关JDK8新特性以前写了三篇博客:html

一、java代码之美(1)---Java8 Lambdajava

二、java代码之美(2)---Java8 Streamapp

三、java代码之美(13)--- Predicate详解ide

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

1、概述

Jdk8以后新增的一个重要的包 : java.util.functionui

该包下全部的接口都是函数式接口, 按分类主要分为四大接口类型: FunctionConsumerPredicateSupplier。有关Predicate这里再也不讲解,由于上面有单独写过一篇博客。this

延伸以下code

这里也仅仅是展现一部分,咱们看看java.util.function包下htm


2、Consumer

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

一、源码

在源码中只有两个方法,一个抽象方法,一个默认方法。

@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); };
    }
}

二、使用示例

public static void main(String[] args) {
        testConsumer();
        testAndThen();
    }
    /**
     * 一个简单的平方计算
     */
    public static void testConsumer() {
        //设置好Consumer实现方法
        Consumer<Integer> square = x -> System.out.println("平方计算 : " + x * x);
        //传入值
        square.accept(2);
    }
    /**
     * 定义3个Consumer并按顺序进行调用andThen方法
     */
    public 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。

三、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) {
        //假设这里有个集合,集合里的对象有个status属性,如今我想对这个属性赋值一个固定值
        List<Pension> pensionList = new ArrayList<>();
        //一、传统的经过for循环添加
        for (Pension pension : pensionList) {
            pension.setStatus(1);
        }
        //二、经过forEach的Consumer添加
        pensionList.forEach(x -> x.setStatus(1));
    }

这样一比较是否是代码简洁了点,这就是Consumer是咱们代码带来简洁的地方。


3、Supplier

做用 提早定义可能返回的一个指定类型结果,等须要调用的时候再获取结果。

一、源码

@FunctionalInterface
public interface Supplier<T> {

    /**
     * 只有这一个抽象类
     */
    T get();
}

源码很是简单。

二、JDK8使用

在JDK8中Optional对象有使用到

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

咱们看下源码

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这里就很少说,接下来会单独写一篇博客。


4、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();
    }

    /**
     * 一、apply 示例
     */
    private static void applyTest() {
        //示例1:定义一个funciton,实现将String转换为Integer
        Function<String, Integer> function = x -> Integer.parseInt(x);
        Integer a = function.apply("100");
        System.out.println(a.getClass());
        // 结果:class java.lang.Integer
    }

    /**
     * 二、andThen 示例
     */
    private static void andThenTest() {
        //示例2:使用andThen() 实现一个函数 y=10x + 10;
        //先执行 10 * x
        Function<Integer, Integer> function2 = x -> 10 * x;
        //经过andThen在执行 这里的x就等于上面的10 * x的值
        function2 = function2.andThen(x -> x + 10);
        System.out.println(function2.apply(2));
        //结果:30

    }

    /**
     * 三、compose 示例
     */
    private static void composeTest() {
        //示例3:使用compose() 实现一个函数 y=(10+x)2;
        Function<Integer, Integer> function3 = x -> x * 2;
        //先执行 x+10 在执行(x+10)*2顺序与上面相反
        function3 = function3.compose(x -> x + 10);
        System.out.println(function3.apply(3));
        //结果:26
    }

    /**
     * 四、综合示例
     */
    private static void test() {

//示例4:使用使用compose()、andThen()实现一个函数 y=(10+x)*2+10;
        //执行第二步
        Function<Integer, Integer> function4 = x -> x * 2;
        //执行第一步
        function4 = function4.compose(x -> x + 10);
        //执行第三步
        function4 = function4.andThen(x -> x + 10);
        System.out.println(function4.apply(3));
       //结果:36

    }

三、JDK8使用

有两个地方很经常使用

一、V HashMap.computeIfAbsent(K , Function<K, V>) // 简化代码,若是指定的键还没有与值关联或与null关联,使用函数返回值替换。
二、<R> Stream<R> map(Function<? super T, ? extends R> mapper); // 转换流

computeIfAbsent使用示例

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(1,"张三","男",38));
        persionList.add(new Person(2,"小小","女",2));
        persionList.add(new Person(3,"李四","男",65));

        //一、只取出该集合中全部姓名组成一个新集合(将Person对象转为String对象)
        List<String> nameList=persionList.stream().map(Person::getName).collect(Collectors.toList());
        System.out.println(nameList.toString());
        }

代码是否是又简洁了。

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

通常咱们也会不多去定义一个方法,方法参数包含函数接口。咱们更重要的是学会使用JDk8中带有函数式接口参数的方法,来简化咱们的代码。

参考

一、JDK1.8函数式接口Function、Consumer、Predicate、Supplier

二、JAVA 8 函数式接口




你若是愿意有所做为,就必须善始善终。(25)
相关文章
相关标签/搜索