如何高效实现DTO类27个字段的空值与空字符串检查?
优化DTO字段空值检查的几种高效方案
1. 封装通用工具方法+Lambda表达式
针对非空判断+赋值的重复逻辑,封装一个通用工具方法,结合Lambda表达式简化代码,既保留直观性又减少重复:
import org.springframework.util.ObjectUtils; import java.util.function.Consumer; public class BuilderHelper { public static <T> void setIfNotEmpty(T value, Consumer<T> setter) { if (!ObjectUtils.isEmpty(value)) { setter.accept(value); } } }
业务代码中调用方式:
BuilderHelper.setIfNotEmpty(updateRequest.getSettingType(), builder::setSettingType); BuilderHelper.setIfNotEmpty(updateRequest.getSettingCode(), builder::setSettingCode); BuilderHelper.setIfNotEmpty(updateRequest.getExecutionEndDate(), builder::setExecutionEndDate); BuilderHelper.setIfNotEmpty(updateRequest.getStartToday(), builder::setStartToday); // 剩余23个字段只需按此格式添加一行即可
优点:无额外依赖,代码简洁直观,运行时无性能损耗;缺点:仍需逐个字段声明,但相比原硬编码方式已大幅减少重复代码。
2. 利用Java反射批量处理
通过反射遍历DTO的字段,自动完成非空判断和赋值,无需为每个字段编写硬编码逻辑:
import org.springframework.util.ObjectUtils; import java.lang.reflect.Field; import java.lang.reflect.Method; public void populateBuilder(UpdateRequest updateRequest, EntityBuilder builder) { Field[] fields = UpdateRequest.class.getDeclaredFields(); for (Field field : fields) { try { // 适配boolean类型的isXXX和普通类型的getXXX方法 Method getter = getGetterMethod(field, UpdateRequest.class); Object value = getter.invoke(updateRequest); if (!ObjectUtils.isEmpty(value)) { Method setter = getSetterMethod(field, EntityBuilder.class); setter.invoke(builder, value); } } catch (Exception e) { // 处理字段无对应getter/setter等异常场景 e.printStackTrace(); } } } // 辅助方法:获取getter private Method getGetterMethod(Field field, Class<?> clazz) throws NoSuchMethodException { String fieldName = field.getName(); if (field.getType() == boolean.class || field.getType() == Boolean.class) { return clazz.getMethod("is" + capitalize(fieldName)); } else { return clazz.getMethod("get" + capitalize(fieldName)); } } // 辅助方法:获取setter private Method getSetterMethod(Field field, Class<?> clazz) throws NoSuchMethodException { String setterName = "set" + capitalize(field.getName()); return clazz.getMethod(setterName, field.getType()); } // 辅助方法:首字母大写 private String capitalize(String name) { if (name == null || name.isEmpty()) return name; return name.substring(0, 1).toUpperCase() + name.substring(1); }
优点:一次编码适配所有字段,新增字段无需修改逻辑;缺点:反射存在轻微性能损耗,对字段命名规范(get/is/set前缀)要求严格,需处理反射异常。
3. 使用MapStruct框架生成映射代码
MapStruct是编译期的Bean映射框架,支持通过注解配置非空忽略规则,自动生成高效的映射代码(无反射性能问题):
首先添加Maven依赖:
<dependency> <groupId>org.mapstruct</groupId> <artifactId>mapstruct</artifactId> <version>1.5.5.Final</version> </dependency> <dependency> <groupId>org.mapstruct</groupId> <artifactId>mapstruct-processor</artifactId> <version>1.5.5.Final</version> <scope>provided</scope> </dependency>
定义映射接口:
import org.mapstruct.Mapper; import org.mapstruct.MappingTarget; import org.mapstruct.NullValueCheckStrategy; import org.mapstruct.NullValuePropertyMappingStrategy; @Mapper(nullValueCheckStrategy = NullValueCheckStrategy.ALWAYS, nullValuePropertyMappingStrategy = NullValuePropertyMappingStrategy.IGNORE) public interface UpdateRequestMapper { void updateBuilderFromRequest(UpdateRequest updateRequest, @MappingTarget EntityBuilder builder); }
业务代码中调用:
// 注入映射接口实例(Spring环境下可直接@Autowired) private UpdateRequestMapper mapper = UpdateRequestMapper.INSTANCE; // 业务逻辑中调用 mapper.updateBuilderFromRequest(updateRequest, builder);
优点:编译期生成原生Java代码,性能优异,注解配置灵活,支持复杂映射场景;缺点:需要引入第三方框架,学习少量注解规则。
内容的提问来源于stack exchange,提问作者Doyel Mishra
相关产品推荐
相关产品推荐

