函数式编程接口Consumer

作者:木子小三金
链接:https://www.jianshu.com/p/63771441ba31

 

从JDK8开始java支持函数式编程,JDK也提供了几个常用的函数式接口,这篇主要介绍Consumer接口。
文本介绍的顺序依次为:

  • 源码介绍
  • 使用实例
  • jdk内对Consumer的典型使用
  • 扩展类介绍
  • 使用方案大猜想

源码介绍

 

package java.util.function;

import java.util.Objects;

/**
 * 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.
 *
 * 表示“接受一个参数输入且没有任何返回值的操作“。不同于其它的函数式接口,Consumer期望通过方法的实现来执行具体的操作。
 *
 * <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> {

    /**
     * Performs this operation on the given argument.
     *
     * 可实现方法,接受一个参数且没有返回值
     * 
     * @param t the input argument
     */
    void accept(T t);

    /**
     * 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.
     *
     * 默认方法,提供链式调用方式执行。执行流程:先执行本身的accept在执行传入参数after.accept方法。
     * 该方法会抛出NullPointerException异常。
     * 如果在执行调用链时出现异常,会将异常传递给调用链功能的调用者,且发生异常后的after将不会在调用。
     * 
     * @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); };
    }
}

源码只有2个方法,也比较容易理解,我们下面来看一下具体的使用方法。

使用实例

 

package jdk8;

import java.util.function.Consumer;

public class ConsumerTest {

    public static void main(String[] args) {
        testConsumer();
        testAndThen();
    }

    /**
     * 一个简单的平方计算
     */
    public static void testConsumer(){
        Consumer<Integer> square = x -> System.out.println("print square : " + x * x);
        square.accept(2);
    }

    /**
     * 定义3个Consumer并按顺序进行调用andThen方法,其中consumer2抛出NullPointerException。
     */
    public static void testAndThen(){
        Consumer<Integer> consumer1 = x -> System.out.println("first x : " + x);
        Consumer<Integer> consumer2 = x -> {
            System.out.println("second x : " + x);
            throw new NullPointerException("throw exception test");
        };
        Consumer<Integer> consumer3 = x -> System.out.println("third x : " + x);

        consumer1.andThen(consumer2).andThen(consumer3).accept(1);
    }
}

下面是执行结果:

 

print square : 4

first x : 1
second x : 1
Exception in thread "main" java.lang.NullPointerException: throw exception test
    at jdk8.ConsumerTest.lambda$testAndThen$2(ConsumerTest.java:27)
    at java.util.function.Consumer.lambda$andThen$0(Consumer.java:65)
    at java.util.function.Consumer.lambda$andThen$0(Consumer.java:65)
    at jdk8.ConsumerTest.testAndThen(ConsumerTest.java:31)
    at jdk8.ConsumerTest.main(ConsumerTest.java:9)

Process finished with exit code 1

在testAndThen()方法的执行结果可以看到打印的顺序和出现异常的情况(third x : 1 并没有输出)
上面只是一个简单的使用,主要为了说明使用方式。对于Consumer的工作实践目前还未使用,并没有好的例子。

jdk内对Consumer的典型使用

在jdk内对Consumer的典型使用非foreach莫属了(在 java.lang.Iterable内),下面是源码:

 

/**
     * Performs the given action for each element of the {@code Iterable}
     * until all elements have been processed or the action throws an
     * exception.  Unless otherwise specified by the implementing class,
     * actions are performed in the order of iteration (if an iteration order
     * is specified).  Exceptions thrown by the action are relayed to the
     * caller.
     *
     * @implSpec
     * <p>The default implementation behaves as if:
     * <pre>{@code
     *     for (T t : this)
     *         action.accept(t);
     * }</pre>
     *
     * @param action The action to be performed for each element
     * @throws NullPointerException if the specified action is null
     * @since 1.8
     */
    default void forEach(Consumer<? super T> action) {
        Objects.requireNonNull(action);
        for (T t : this) {
            action.accept(t);
        }
    }

方法接收一个Consumer对象,对this集合执行循环相同的操作

TODO:除Iterable外还有很多地方使用到了Consumer,待后续使用到在添加。

扩展类介绍

Consumer的accept只接受一个参数,那如果要是想使用多个参数要怎么办?jdk8又提供了一个BiConsumer接口类,该类与Consumer的区别是可以接受2个参数。

jdk8还对Consumer和BiConsumer各提供了3个常用的相关接口类,见下表:

类名描述
IntConsumer接受单个int型参数的Consumer操作
DoubleConsumer接受单个double型参数的Consumer操作
LongConsumer接受单个long型参数的Consumer操作
ObjIntConsumer接受2个int型参数的Consumer操作,不支持andThen方法
ObjDoubleConsumer接受2个double型参数的Consumer操作,不支持andThen方法
ObjLongConsumer

接受2个long型参数的Consumer操作,不支持andThen方法

 

猜想1: 装饰器模式

首先我们简单的温习一下装饰器模式

意图:动态地给一个对象添加一些额外的职责。就增加功能来说,装饰器模式相比生成子类更为灵活。

主要解决:一般的,我们为了扩展一个类经常使用继承方式实现,由于继承为类引入静态特征,并且随着扩展功能的增多,子类会很膨胀。

何时使用:在不想增加很多子类的情况下扩展类。

实际案例场景举例:

       我们有一个业务需求,我们的商城,客户购买了很多东西,需要进行结账,这个时候我们需要给客户一个总账单和具体商品的明细,客户的订单是不同类别的,我们数据库将不同类别的商品存了不同的表;

       

//用枚举指定执行行为类
private  Map<String, Consumer<? super T> queryAction>  atcionMap = new HashMap; 



//Order 类中包含   findList
@Override
public void queryOrderDetail(Order order) {
     List<String> findList = order.getFindList();
     for(String key: findList){
        if(atcionMap.contain(key)){
            atcionMap.get(key).accept(order);
        }
    }
}



static{
    atcionMap.put("fresh",order -> {
            //todo 查询生鲜订单
        }) ;

    atcionMap.put("costume",order -> {
            //todo 查询服饰订单
        }) 
}

 

猜想2: 责任链模式

 

  • 2
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值