支持空值多参数的Mobile搜索方法实现优化问询
嘿,这种硬编码覆盖16种参数组合的方式确实太繁琐了,不仅写起来累,后续维护或者加新参数的时候简直是噩梦!给你几个更优雅的实现思路,能彻底摆脱这种“组合地狱”:
方案1:Java Stream 流式过滤(最直接的改造)
利用Stream的filter方法,逐个对每个参数做非空判断+匹配,每个条件独立,完全不用管参数组合数。代码简洁直观,改造成本最低:
import java.util.Set; import java.util.stream.Collectors; public class MobileSearchService { public Set<Mobile> search(Set<Mobile> mobiles, OperatingSystem os, Brand brand, Display display, Style style) { return mobiles.stream() // 操作系统非空才匹配,为空则跳过该条件 .filter(mobile -> os == null || mobile.getOperatingSystem().equals(os)) // 品牌参数同理 .filter(mobile -> brand == null || mobile.getBrand().equals(brand)) // 屏幕参数同理 .filter(mobile -> display == null || mobile.getDisplay().equals(display)) // 风格参数同理 .filter(mobile -> style == null || mobile.getStyle().equals(style)) .collect(Collectors.toSet()); } }
这种方式的优势在于:
- 代码线性,每个条件逻辑独立,可读性极强
- 新增参数只需要加一行
filter,完全不用考虑组合数 - 底层Stream的并行处理还能轻松优化性能(如果数据集很大)
方案2:Predicate 组合(适合复杂条件扩展)
如果后续可能要加更复杂的搜索逻辑(比如范围查询、模糊匹配),可以把每个非空参数的判断封装成Predicate,然后统一组合过滤:
import java.util.ArrayList; import java.util.List; import java.util.Set; import java.util.function.Predicate; import java.util.stream.Collectors; public class MobileSearchService { public Set<Mobile> search(Set<Mobile> mobiles, OperatingSystem os, Brand brand, Display display, Style style) { List<Predicate<Mobile>> predicates = new ArrayList<>(); if (os != null) { predicates.add(mobile -> mobile.getOperatingSystem().equals(os)); } if (brand != null) { predicates.add(mobile -> mobile.getBrand().equals(brand)); } if (display != null) { predicates.add(mobile -> mobile.getDisplay().equals(display)); } if (style != null) { predicates.add(mobile -> mobile.getStyle().equals(style)); } // 所有非空条件都要满足 return mobiles.stream() .filter(mobile -> predicates.stream().allMatch(pred -> pred.test(mobile))) .collect(Collectors.toSet()); } }
这种方式的好处是:
- 每个条件逻辑被单独封装,方便复用和修改
- 后续可以轻松添加复杂Predicate(比如
mobile.getPrice() < maxPrice) - 还能灵活调整条件关系(比如把
allMatch改成anyMatch实现“或”逻辑)
方案3:Builder模式封装搜索参数(优化调用体验)
如果参数数量还可能增加,或者想让调用方的代码更清晰,可以先把搜索参数封装成一个Builder类:
// 搜索条件封装类 public class MobileSearchCriteria { private OperatingSystem os; private Brand brand; private Display display; private Style style; private MobileSearchCriteria(Builder builder) { this.os = builder.os; this.brand = builder.brand; this.display = builder.display; this.style = builder.style; } // Getter方法 public OperatingSystem getOs() { return os; } public Brand getBrand() { return brand; } public Display getDisplay() { return display; } public Style getStyle() { return style; } // Builder内部类 public static class Builder { private OperatingSystem os; private Brand brand; private Display display; private Style style; public Builder os(OperatingSystem os) { this.os = os; return this; } public Builder brand(Brand brand) { this.brand = brand; return this; } public Builder display(Display display) { this.display = display; return this; } public Builder style(Style style) { this.style = style; return this; } public MobileSearchCriteria build() { return new MobileSearchCriteria(this); } } }
然后改造search方法:
public class MobileSearchService { public Set<Mobile> search(Set<Mobile> mobiles, MobileSearchCriteria criteria) { return mobiles.stream() .filter(mobile -> criteria.getOs() == null || mobile.getOperatingSystem().equals(criteria.getOs())) .filter(mobile -> criteria.getBrand() == null || mobile.getBrand().equals(criteria.getBrand())) .filter(mobile -> criteria.getDisplay() == null || mobile.getDisplay().equals(criteria.getDisplay())) .filter(mobile -> criteria.getStyle() == null || mobile.getStyle().equals(criteria.getStyle())) .collect(Collectors.toSet()); } }
调用的时候就会非常清晰:
// 比如只按品牌和屏幕搜索 MobileSearchCriteria criteria = new MobileSearchCriteria.Builder() .brand(Brand.SAMSUNG) .display(Display.AMOLED) .build(); Set<Mobile> result = searchService.search(allMobiles, criteria);
这种方式的优势在于:
- 避免了方法参数过多的问题,调用方代码可读性大幅提升
- 搜索条件可以复用、修改,不用每次传一堆零散参数
- 后续加新参数只需要在Builder里加对应方法,对现有代码侵入极小
内容的提问来源于stack exchange,提问作者Mounika Gaja
相关产品推荐
相关产品推荐

