• jdk8函数式接口——Consumer介绍


    Consumer介绍与实例分析
    函数式接口:@FunctionalInterface
    Consumer(消费者)
    函数式接口:@FunctionalInterface
    自从jdk8提供了函数式接口这一新的特性,极大地精简了java开发的方式。而在jdk8之前的版本,函数仅仅只能传递参数,而不能将一个函数或者说是行为传递过去,这意味着我们在调用某个函数时,该函数所表示的执行功能已经很明确了,对于lambda表达式来说,函数的调用,是将函数的行为传递过去,真正执行的是调用时传递的行为。@FunctionalInterface注解是标识一个接口是函数式接口。那么什么样的接口是函数式接口呢?
    下面是@FunctionalInterface的注释说明:

    Conceptually, a functional interface has exactly one abstract
    method. Since {@linkplain java.lang.reflect.Method#isDefault()
    default methods} have an implementation, they are not abstract. If
    an interface declares an abstract method overriding one of the
    public methods of {@code java.lang.Object}, that also does
    <em>not</em> count toward the interface's abstract method count
    since any implementation of the interface will have an
    implementation from {@code java.lang.Object} or elsewhere.
    Note that instances of functional interfaces can be created with
    lambda expressions, method references, or constructor references.

    该注释说了,一个函数式接口应该只有一个抽象方法,对于default methods,是有一个实现,所以它们不是抽象的,这里就说明了jdk8的接口支持方法的实现。如果一个接口声明了一个抽象方法,该方法是被Object类给重写的,那么它不会为该接口的抽象方法增加,因为在Object或者别处会有一个具体的实现。函数式接口的实例可以通过lambda表达式,方法引用,构造方法引用的方式创建出来。这里我们就理解了函数式接口和lambda表达式之间的关系了。下面我主要讲解一个函数式接口Consumer的用法。

    Consumer(消费者)
    对于Consumer这个接口,我们来看一下它提供的抽象方法是什么?

    /**
    * Performs this operation on the given argument.
    *
    * @param t the input argument
    */
    void accept(T t);

    accept(T t),接受一个参数,没有返回值。举一个例子:

    List<Integer> list = Lists.newArrayList(1, 2, 3, 4, 5, 6, 7, 8, 9);
    
    // 通过lambda表达式构造出Consumer对象
    
    list.forEach(i -> System.out.println(i));

    这里是通过lambda表达式构造出Consumer对象,将list中每一个元素,传递给consumer,执行打印的操作,我再把这个例子做一个变化

    // 通过lambda表达式构造出Consumer对象
    
    list.forEach(i -> System.out.println(i * 2));


    这里打印的元素是乘2后的结果,这就说明了通过lambda表达式,我们传递的是行为,accept(T t)方法只负责接收一个参数,至于要做什么,是我们再调用的时候,把行为传递过去。
    另外还可以使用方法引用的方式来调用Consumer的accept方法。

    // 通过方法引用的方式构造出Consumer对象
    list.forEach(System.out::println);

    比如将给定的一批用户里面的名称为"lisi"的用户都给打包起来

    /**
     * 此处使用lombok插件(值得了解)
     */
    @Data
    @Accessors(chain = true)
    @AllArgsConstructor
    public class Person {
        private Integer age;
        private String name;
    }
    
    List<Person> lisiList = new ArrayList<>();
    Consumer<Person> consumer  = x -> {
        if (x.getName().equals("lisi")){
            lisiList.add(x);
        }
    };
    Stream.of(
            new Person(21,"zhangsan"),
            new Person(22,"lisi"),
            new Person(23,"wangwu"),
            new Person(24,"wangwu"),
            new Person(23,"lisi"),
            new Person(26,"lisi"),
            new Person(26,"zhangsan")
    ).forEach(consumer);
    
    System.out.println(JSON.toJSONString(lisiList));

    结果为:

    [{"age":22,"name":"lisi"},{"age":23,"name":"lisi"},{"age":26,"name":"lisi"}]


    这里也可以实现遍历每一个元素并打印出来,这是通过方法引用的方式来构造出的Consumer对象。"::"这里两个连续的冒号,是jdk8支持的语法,可以自动定位到具体的函数式接口,这里就可以自动定位到Consumer。
    Consumer中还提供了一个默认方法,andThen,来看一下

    /**
    * Returns a composed {@code Consumer} that performs, in sequence, this
    * operation followed by the {@code after} operation. If performing either
    * operation throws an exception, it is relayed to the caller of the
    * composed operation. If performing this operation throws an exception,
    * the {@code after} operation will not be performed.
    *
    * @param after the operation to perform after this operation
    * @return a composed {@code Consumer} that performs in sequence this
    * operation followed by the {@code after} operation
    * @throws NullPointerException if {@code after} is null
    */
    default Consumer<T> andThen(Consumer<? super T> after) {
    Objects.requireNonNull(after);
    return (T t) -> { accept(t); after.accept(t); };
    }



    该方法默认实现,它接收一个Consumer对象,同时会返回一个Consumer对象,返回的Consumer对象还可以继续调用andThen方法,这样该方法就实现了将执行操作给串行化。举个例子:

    public static void main(String[] args) {
    ConsumerTest02 test = new ConsumerTest02();
    List<Integer> list = Lists.newArrayList(1, 2, 3, 4, 5, 6, 7, 8, 9);
    test.print(list, item -> System.out.print(" consumer1:" + item * 2), item -> System.out.print(" consumer2:" + item * 3));
    }
    
    /*
    andThen方法, 将参数传递给调用者执行accept方法,然后再传给第二个consumer执行accept方法。
    */
    public void print(List<Integer> list, IntConsumer con1, IntConsumer con2) {
    list.forEach(item -> con1.andThen(con2).accept(item));
    }

    该示例构造了两个Consumer对象,通过consumer的andThen方法,将两个操作给串行起来,对于list中每个元素,都会先执行con1的appect方法,再执行con2的accept方法。
    打印结果:

    consumer1:2 consumer2:3 consumer1:4 consumer2:6 consumer1:6 consumer2:9 consumer1:8 consumer2:12 consumer1:10 consumer2:15 consumer1:12 consumer2:18 consumer1:14 consumer2:21 consumer1:16 consumer2:24 consumer1:18 consumer2:27
    1

    比如将给定的一批用户里面的名称为"lisi"且年龄大于22岁的用户都给打包起来

    List<Person> lisiList = new ArrayList<>();
    Consumer<Person> consumer  = x -> {
        if (x.getName().equals("lisi")){
            lisiList.add(x);
        }
    };
    consumer = consumer.andThen(
            x -> lisiList.removeIf(y -> y.getAge() < 23)
    );
    Stream.of(
            new Person(21,"zhangsan"),
            new Person(22,"lisi"),
            new Person(23,"wangwu"),
            new Person(24,"wangwu"),
            new Person(23,"lisi"),
            new Person(26,"lisi"),
            new Person(26,"zhangsan")
    ).forEach(consumer);
    
    System.out.println(JSON.toJSONString(lisiList));
    }

    结果为:

    [{"age":23,"name":"lisi"},{"age":26,"name":"lisi"}]

    与Consumer相关的接口

    • BiConsumer<T, U>

    处理一个两个参数

    • DoubleConsumer

    处理一个double类型的参数

    • IntConsumer

    处理一个int类型的参数

    • LongConsumer

    处理一个long类型的参数

    • ObjIntConsumer

    处理两个参数,且第二个参数必须为int类型

    • ObjLongConsumer

    处理两个参数,且第二个参数必须为long类型

    原文链接:

    https://blog.csdn.net/rz_0212/article/details/89575600

    https://www.cnblogs.com/coderxx/p/11182892.html

  • 相关阅读:
    tpshop添加后台菜单
    TPshop添加后台菜单
    TPshop隐藏index.php
    TPshop表结构
    TPshop下载安装
    django学习2 视图和模板
    java 运行时常量、编译时常量、静态块执行顺序
    java 比较几种常见循环方式的优劣
    linux下svn命令大全
    linux为用户配置java环境变量
  • 原文地址:https://www.cnblogs.com/yuluoxingkong/p/16013262.html
Copyright © 2020-2023  润新知