java如何使用函数式编程优雅处理根据ID设置Name

1. 背景

系统中很多数据表只存储了数据的ID,没有存储其名字,但前端展示需要展示其名字。

比如

  1. 工单表只存储了创建人,更新人的ID,列表需要展示 创建人,更新人的中文名字。
  2. 订单表只存储了机构的ID,产品的编码,列表需要展示机构名字,产品的名字。

2. 常规代码

java 复制代码
// 设置工单创建人名字
{
    List<WorkOrderQueryResp> workOrderList = new ArrayList();
    Set<Long> getCreatorIdSet = workOrderList.stream().map(WorkOrderQueryResp::getCreatorId).collect(Collectors.toSet());
    if (CollectionUtils.isNotEmpty(getCreatorIdSet)) {
        Map<Long, String> createNameMap = userService.queryNameByUserIds(getCreatorIdSet);
        for (WorkOrderQueryResp orderDTO : workOrderList) {
            orderDTO.setCreatorName(createNameMap.get(orderDTO.getCreatorId()));
        }
    }
}
// 设置呼叫数据创建人名字
{
    List<CallPageResp> pageResps = new ArrayList();
    Set<Long> getCreatorIdSet = pageResps.stream().map(CallPageResp::getCreatorId).collect(Collectors.toSet());
    if (CollectionUtils.isNotEmpty(getCreatorIdSet)) {
        Map<Long, String> createNameMap = userService.queryNameByUserIds(getCreatorIdSet);
        for (CallPageResp callPageResp : pageResps) {
            callPageResp.setCreatorName(createNameMap.get(callPageResp.getCreatorId()));
        }
    }

我发现 这类根据ID设置名字的处理步骤是相似的

  1. 遍历List获取Id,存储成List或Set。
  2. 根据多个Id查询一个Map<Id,Name>的数据
  3. 遍历List,从Map<Id,Name> 获取Id对应名字设置

很多时候只是处理的对象类型不同

3. 使用函数式编程对这类行为进行抽象

typescript 复制代码
/**
 * 
 * @param data 数据
 * @param nameSet 用于设置名称的函数(给对象设置名字)
 * @param idGet idGet 用于获取 ID 的函数(从对象中提取 ID)
 * @param getNameByIdsFunction 用于批量查询名称的函数(根据 ID 集合获取 ID - 名称映射)
 * @param <T>
 * @param <KEY>
 */
public static <T, KEY> void setName(List<T> data, BiConsumer<T, String> nameSet, Function<T, KEY> idGet,
                                    Function<Set<KEY>, Map<KEY, String>> getNameByIdsFunction) {
    if (CollectionUtils.isEmpty(data)) {
        return;
    }
    // 1 遍历List<Data>获取ID
    Set<KEY> filterIds = data.stream().map(idGet::apply).filter(Objects::nonNull).collect(Collectors.toSet());
    if (CollectionUtils.isEmpty(filterIds)) {
        return;
    }
    if (CollectionUtils.isNotEmpty(filterIds)) {
       // 2. 根据多个Id查询一个Map<Id,Name>的数据
        Map<KEY, String> idNameMap = getNameByIdsFunction.apply(filterIds);
        if (idNameMap == null) {
            idNameMap = Collections.emptyMap();
        }
       // 3. 遍历List<Data>,从Map<Id,Name> 获取Id对应名字设置
        data.forEach(e -> nameSet.accept(e, idNameMap.get(idGet.apply(e))));
    }
}

使用函数式编程简化后的代码如下

java 复制代码
// 设置工单创建人名字
{
    ListSetNameByIdUtil.setName(workOrderList,WorkOrderQueryResp::setCreatorName,WorkOrderQueryResp::getCreatorId,
    userService::queryNameByUserIds)
}
// 设置呼叫数据创建人名字
{
    ListSetNameByIdUtil.ssetName(pageResps,CallPageResp::setCreatorName,CallPageResp::getCreatorId,
    userService::queryNameByUserIds)
}

使用函数式编程抽象后,只需要一行代码就可以完成根据ID设置名字的操作,可以兼容多种返回对象类型。

可以向上再封装一层,写在UserService,后续有这类需要需求只需要写一行代码。

kotlin 复制代码
public <T> void setUserName(List<T> data, BiConsumer<T, String> nameSet, Function<T, Long> idGet) {
    ListSetNameByIdUtil.setName(data, nameSet, idGet, this::queryNameByUserIds);
}

总结

函数式编程用于封装共同的行为太nice了

相关推荐
精品源码屋12 分钟前
基于JAVA17的仿向日葵远程控制软件源码+最新自研完整版
后端
叉烧钵钵鸡16 分钟前
Java ++i 与 i++ 底层原理
java·开发语言·后端
JuiceFS26 分钟前
JuiceFS on Windows: 首个 Beta 版的探索与优化之路
后端·云原生·云计算
JavaGuide29 分钟前
美团OC了,给的挺多!很满意!!
后端·面试
excel1 小时前
Nuxt 3 + PWA 通知完整实现指南(Web Push)
前端·后端
用户4099322502121 小时前
BackgroundTasks 如何巧妙驾驭多任务并发?
后端·github·trae
ZLlllllll01 小时前
常见的框架漏洞(Thinkphp,spring,Shiro)
java·后端·spring·常见的框架漏洞
ZS8851 小时前
【AI】 Clickhouse MergeTree基本原理
后端
陈随易2 小时前
为VSCode扩展开发量身打造的UI库 - vscode-elements
前端·后端·程序员