jdk8 | BiConsumer<T,U>实践应用

BiConsumer<T, U>的方法void accept(T t, U u)提供了两个输入参数的执行,它还有提供一个输入参数的Consumer<T>的方法void accept(T t)

1.场景再现

背景是这样的,通常对于数据分类或者检索,我们可以基于标签的形式,以便归类,并提供检索功能。

![ER图]](https://img-blog.csdnimg.cn/20200828173940215.png?x-oss-process=image/watermark,type_ZmFuZ3poZW5naGVpdGk,shadow_10,text_aHR0cHM6Ly9ibG9nLmNzZG4ubmV0L3NoaWNoZW4yMDEw,size_16,color_FFFFFF,t_70#pic_center)

如上图所示,几张业务表呢,标签存在一个字表中,通过relation_id关联主表id,buz_type标示业务类型(即哪张主表),页面查询时呢,需要展示该数据的相关标签。

UI样例

如上图,页面展示数据时,需要把每条数据对应的标签一并展示。

既然多个模块的数据查询都需要展示标签,而标签是单独存在一张表中,标签表通过buz_typerelation_id可以定位某业务表一条数据的标签,一条数据可以设置多条标签。

/**
 * 对相关查询的VO绑定标签
 * @param tuple 数据传输通道容器
 * @param function 回调函数,返回集合元素对象,让调用方返回对应的主键id
 * @param consumer 接口,返回获取的tags
 */
public <T,R> void bindTags(TwoTuple<Integer,List<T>> tuple, Function<T,R> function, BiConsumer<T,List<String>> consumer){
    try {
        TagForm form = new TagForm();
        form.setBuzType(tuple.getA());
        List<Tag> tagList = this.pdTagService.queryList(form);
        if(CollectionsTools.isNotEmpty(tagList)){
            Map<Integer,String> tagMap = tagList.stream().collect(Collectors.toMap(Tag::getSourceId, Tag::getTags));
            tuple.getB().forEach(rule -> {
                String tags = tagMap.get(function.apply(rule));
                if(StringTools.isNotEmpty(tags)){
                    consumer.accept(rule, Arrays.asList(tags.split(",")));
                }
            });
        }
    } catch (Exception e) {
        log.error("{}设置标签异常,tuple={}",JSON.toJSON(tuple),e);
    }
}

如上述代码,该方法void bindTags(TwoTuple<Integer,List<T>> tuple, Function<T,R> function, BiConsumer<T,List<String>> consumer)提供了对输入的数据
进行绑定标签的功能特性。下述对参数及进行简单介绍:

  • TwoTuple<Integer,List> tuple:支持两个参数的管道容器,Integer类型即我们要查询标签的业务类型buz_typeList<T>即我们要绑定的数据集。
  • Function<T,R> function:即我们关注的数据id,通过ID我们可以得到相应tagMap中对应的标签。
  • BiConsumer<T,List> consumer:支持两个输入参数的执行,T即我们的数据集对象,List<String>即我们查询得到对应数据集记录的标签集合。

上述封装的这个方法,通过内部包装通过输入的数据集和业务类型,根据业务类型查询出标签,然后给每一个数据集记录对象绑定标签,而方法内部不关注
关联id是哪个参数,通过Function<T,R> function提供回调机制,让调用方给出,同样对于处理的标签,也通过BiConsumer<T,List<String>> consumer交由回调函数
决定绑定到数据集对象的某个属性。

我们看一下调用发的代码:

 public Result<PageVO<ArgControlVo>> loadRecords(PageForm<ArgControlForm> form) {
    if (form.getForm() != null && !StringUtils.isEmpty(form.getForm().getTag())) {
        //默认是参数类型
        form.getForm().setClassify(15);
    }
    List<ArgControlVo> voList = new ArgControlConverter().convertList(argControlService.queryByPage(form));
    if (CollectionsTools.isEmpty(voList)) {
        return Result.failInEmptyRecord(null);
    }
    int count = voList.size();
    if (form.isPaging()) {
        count = argControlService.queryCount(form);
    }
    //查询标签
    commonComponent.bindTags(TwoTuple.newInstance(TagConstant.BuzTypeEnum.SY_ARG_CONTROL.getIndex(),voList),
            rule->Integer.valueOf(rule.getId()),(rule,tags)->rule.setTags(tags));
    return Result.suc(new PageVO<>(count, voList));
}

上述的commonComponent.bindTags即我们提前的组件类,通过该组件封装一个公共方法bindTags,外部通过注入commonComponent这个bean,并调用该方法。

2.BiConsumer<T, U>

@FunctionalInterface
public interface BiConsumer<T, U> {
    /**
     * Performs this operation on the given arguments.
     *
     * @param t the first input argument
     * @param u the second input argument
     */
    void accept(T t, U u);
    /**
     * Returns a composed {@code BiConsumer} 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 BiConsumer} that performs in sequence this
     * operation followed by the {@code after} operation
     * @throws NullPointerException if {@code after} is null
     */
    default BiConsumer<T, U> andThen(BiConsumer<? super T, ? super U> after) {
        Objects.requireNonNull(after);

        return (l, r) -> {
            accept(l, r);
            after.accept(l, r);
        };
    }
}

方法void accept(T t, U u);通过回调给调用方两个参数T、U,并执行该操作accept

3.总结

对于抽象出的方法,我们只关注数据的处理,处理的数据通过回调函数,交由调用方去处理,这时我们可以通过BiConsumer<T, U>或者Consumer<T>。当然,如果我们期望支持三个参数,或者多个,我们也可以进一步封装一个泛型对象,譬如上述的Tuple,
比如三个参数我们可以定义一个泛型类Tuple<A,B,C>

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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值