如何简化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
相关产品推荐
相关产品推荐

