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了

相关推荐
阿正的梦工坊7 小时前
【Rust】02-变量、不可变性与基础类型
开发语言·后端·rust
我叫黑大帅9 小时前
通过php 中的Route:: 的写法了解什么是静态类调用
后端·面试·php
JS菌9 小时前
AI Agent 沙箱双层防护体系:从权限过滤到内核隔离的完整实现
前端·人工智能·后端
IT空门:门主10 小时前
Spring 注入三剑客:@Resource、@Autowired、@RequiredArgsConstructor 到底该用哪个?
java·后端·spring
ServBay10 小时前
云端 AI 蜜月期宣告结束,为什么 2026 年开发者转向本地优先架构
后端·ai编程
IT_陈寒10 小时前
Vite这个坑我帮你踩了,动态导入居然这样才生效
前端·人工智能·后端
Sam_Deep_Thinking10 小时前
Spring Boot 的启动原理是什么?
java·spring boot·后端
南部余额10 小时前
Spring WebClient 从入门到精通
java·后端·spring
摇滚侠10 小时前
Spring 零基础入门到进阶 基于注解管理 Bean 38-43
xml·java·后端·spring·intellij-idea
SamDeepThinking11 小时前
我们当年是如何真实落地BFF的?
java·后端·架构