You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

如何简化ProfileDto空字段赋值逻辑?替代多if判断方案

问题

想找一种更简洁的方式检查ProfileDto字段是否为空,需求是若ProfileDto字段为空则用数据库User对象对应字段值填充,不为空则保留原Dto值。网上搜的都是检查单个或所有字段为空的方案,不符合需求。

背景与当前实现

当前代码需要逐个字段判断null并赋值,字段多了会写大量if判断:

private void setEmptyFieldsForUpdatedUser(User user, ProfileDto profileDto) {
    String newFirstName = profileDto.getFirstName();
    String newLastName = profileDto.getLastName();
    String newEmailAdres = profileDto.getEmail();
    String oldPassword = profileDto.getPassword();
    String newPassword = profileDto.getNewPassword();

    if (newFirstName == null) {
        profileDto.setFirstName(user.getFirstName());
    }
    if (newLastName == null) {
        profileDto.setLastName(user.getLastName());
    }
    if (newEmailAdres == null) {
        profileDto.setEmail(user.getEmail());
    }
}

数据示例

  • 数据库User对象属性:
firstname: dj
lastname : test
email : dj@mail.com
password : qwerty
  • 输入ProfileDto(JSON):
{
    "firstName": "freeman",
    "lastName": null,
    "email": null,
    "password": null,
    "newPassword" : null
}
  • 期望输出:
{
    "firstName": "freeman",
    "lastName": "test",
    "email": "dj@mail.com",
    "password": "qwerty"
}
优化方案

方案1:利用Optional简化单字段判断

Java 8+的Optional可以直接替代if判断,代码更简洁,可读性强,无性能损耗:

private void setEmptyFieldsForUpdatedUser(User user, ProfileDto profileDto) {
    profileDto.setFirstName(Optional.ofNullable(profileDto.getFirstName()).orElse(user.getFirstName()));
    profileDto.setLastName(Optional.ofNullable(profileDto.getLastName()).orElse(user.getLastName()));
    profileDto.setEmail(Optional.ofNullable(profileDto.getEmail()).orElse(user.getEmail()));
    profileDto.setPassword(Optional.ofNullable(profileDto.getPassword()).orElse(user.getPassword()));
}

新增字段时只需添加一行对应代码,维护成本低。

方案2:反射批量处理(适合字段极多的场景)

通过反射遍历Dto字段,自动匹配User的对应字段赋值,新增字段无需修改代码:

private void fillNullFields(User user, ProfileDto dto) throws IllegalAccessException, NoSuchMethodException, InvocationTargetException {
    Field[] dtoFields = ProfileDto.class.getDeclaredFields();
    for (Field dtoField : dtoFields) {
        dtoField.setAccessible(true);
        Object dtoValue = dtoField.get(dto);
        if (dtoValue == null) {
            // 匹配User的字段名(处理Dto首字母大写、User小写的差异)
            String userFieldName = dtoField.getName().replaceFirst("^[A-Z]", m -> m.group().toLowerCase());
            Field userField = User.class.getDeclaredField(userFieldName);
            userField.setAccessible(true);
            Object userValue = userField.get(user);
            
            // 调用Dto的setter方法赋值
            String setterName = "set" + dtoField.getName().substring(0, 1).toUpperCase() + dtoField.getName().substring(1);
            Method setter = ProfileDto.class.getMethod(setterName, dtoField.getType());
            setter.invoke(dto, userValue);
        }
    }
}

注意:如果Dto和User的字段命名规则差异较大,需要调整字段名匹配逻辑;反射存在轻微性能开销,性能敏感场景谨慎使用。

方案3:自定义字段映射集合(兼顾简洁与可控)

预先定义字段映射逻辑的集合,集中管理所有字段的处理规则:

// 定义字段映射的函数接口
@FunctionalInterface
interface FieldMapper {
    void apply(ProfileDto dto, User user);
}

// 集中配置所有字段的映射规则
private static final List<FieldMapper> FIELD_MAPPERS = Arrays.asList(
    (dto, user) -> dto.setFirstName(Optional.ofNullable(dto.getFirstName()).orElse(user.getFirstName())),
    (dto, user) -> dto.setLastName(Optional.ofNullable(dto.getLastName()).orElse(user.getLastName())),
    (dto, user) -> dto.setEmail(Optional.ofNullable(dto.getEmail()).orElse(user.getEmail())),
    (dto, user) -> dto.setPassword(Optional.ofNullable(dto.getPassword()).orElse(user.getPassword()))
);

private void setEmptyFieldsForUpdatedUser(User user, ProfileDto profileDto) {
    FIELD_MAPPERS.forEach(mapper -> mapper.apply(profileDto, user));
}

这种方式把所有字段逻辑集中在一处,新增字段只需在集合中添加一行,既避免了大量分散的if判断,又比反射更可控、无性能问题。


内容的提问来源于stack exchange,提问作者Elias

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.08.10 02:20:28