Java过滤对象null空值 优化Spring Boot接口重复判空逻辑
重复判空代码优化方案
你当前遇到的大量重复null判断是动态搜索接口非常常见的问题,有几种成熟的简化方案,按需选择即可。
方案1:封装非空条件提取+逻辑映射,彻底消除重复if
这个方案完全匹配你提到的「提取非空字段为独立结构」的思路,把判空逻辑和字段处理逻辑解耦:
首先在
SearchRequest类内部封装非空字段提取方法,把所有已赋值的搜索条件统一返回,不用在Controller层挨个判断:- 如果不想用反射,可以直接用
Optional手动收集,逻辑完全可控:
public class SearchRequest { // 原有字段、getter/setter省略 /** * 提取所有非空的搜索条件 * @return key为字段名,value为对应字段值 */ public Map<String, Object> getNonNullConditions() { Map<String, Object> conditions = new HashMap<>(); Optional.ofNullable(type).ifPresent(v -> conditions.put("type", v)); Optional.ofNullable(brand).ifPresent(v -> conditions.put("brand", v)); Optional.ofNullable(date).ifPresent(v -> conditions.put("date", v)); Optional.ofNullable(country).ifPresent(v -> conditions.put("country", v)); Optional.ofNullable(client).ifPresent(v -> conditions.put("client", v)); Optional.ofNullable(airco).ifPresent(v -> conditions.put("airco", v)); Optional.ofNullable(transmission).ifPresent(v -> conditions.put("transmission", v)); Optional.ofNullable(seats).ifPresent(v -> conditions.put("seats", v)); return conditions; } }- 如果后续字段加的多,嫌手动写put麻烦,也可以用反射遍历类字段自动收集,几个字段的场景下反射性能损耗完全可以忽略。
- 如果不想用反射,可以直接用
把每个字段对应的处理逻辑提前注册到映射表中,不用在接口方法里堆if:
@RestController public class CarSearchController { // 字段名 -> 对应处理逻辑的映射 private final Map<String, Consumer<Object>> fieldHandlerMap = new HashMap<>(); @PostConstruct public void initHandlers() { fieldHandlerMap.put("type", val -> { // 原代码中type非空时的dosomething逻辑,val就是searchRequest.getType()的值 }); fieldHandlerMap.put("brand", val -> { // 原代码中brand非空时的dosomething逻辑 }); fieldHandlerMap.put("country", val -> { // 原代码中country非空时的dosomething逻辑 }); // 其余字段照着注册即可 } // 原有依赖注入省略 @PostMapping("/searchCarOptions") public ResponseEntity<Cars> search( @Parameter(description = "some searchRequest") @RequestBody SearchRequest searchRequest) { // 遍历所有非空条件,执行对应处理逻辑 searchRequest.getNonNullConditions().forEach((fieldName, val) -> { Optional.ofNullable(fieldHandlerMap.get(fieldName)) .ifPresent(handler -> handler.accept(val)); }); return ResponseEntity.ok(someService.search(searchRequest)); } }后续新增搜索字段时,只需要在
SearchRequest加对应字段、在getNonNullConditions加收集逻辑、在handlerMap注册对应处理逻辑即可,不用再改接口主流程代码,整洁度提升非常明显。
方案2:持久层框架自带动态查询,无需手写判空
如果你写这堆if判断本质是为了拼接数据库查询条件,完全没必要自己在Controller层做判空,主流持久层框架都自带动态条件拼接能力,自动忽略null值字段:
- 用MyBatis-Plus的话,直接在Service层用条件构造器,第一个参数传判空表达式,为true才会拼接对应SQL条件:
public Page<Car> search(SearchRequest req) { LambdaQueryWrapper<Car> wrapper = Wrappers.lambdaQuery(Car.class) .eq(req.getType() != null, Car::getType, req.getType()) .eq(req.getBrand() != null, Car::getBrand, req.getBrand()) .eq(req.getCountry() != null, Car::getCountry, req.getCountry()) .eq(req.getClient() != null, Car::getClient, req.getClient()) .eq(req.getAirco() != null, Car::getAirco, req.getAirco()) .eq(req.getTransmission() != null, Car::getTransmission, req.getTransmission()) .eq(req.getSeats() != null, Car::getSeats, req.getSeats()) .eq(req.getDate() != null, Car::getProduceDate, req.getDate()); return carMapper.selectPage(req.getPage(), wrapper); } - 用Spring Data JPA的话可以搭配Querydsl或者Specification实现动态查询,同样自动处理null条件,不用手写判空。
方案3:最小改动写法,不调整原有结构
如果你不想大改现有代码结构,只是想简化判空写法,可以直接用Optional的ifPresent方法替换原生的if (xx != null)写法,视觉上会整洁很多:
@PostMapping("/searchCarOptions") public ResponseEntity<Cars> search( @Parameter(description = "some searchRequest") @RequestBody SearchRequest searchRequest) { Optional.ofNullable(searchRequest.getType()).ifPresent(val -> { // dosomething }); Optional.ofNullable(searchRequest.getBrand()).ifPresent(val -> { // dosomething }); Optional.ofNullable(searchRequest.getCountry()).ifPresent(val -> { // dosomething }); // 其余字段同理 return ResponseEntity.ok(someService.search(searchRequest)); }
注意:如果字段除了非空判断,还要做空字符串、空集合的校验,可以把判断逻辑抽成通用工具方法,不用每个地方重复写判断规则。
内容的提问来源于stack exchange,提问作者mesut
相关产品推荐
相关产品推荐

