如果你想避免反射,可以考虑以下方法:
static enum DetailQueryParams {
ITEM("item", d -> d.item),
NAME("name", d -> d.name),
TYPE("type", d -> d.type),
ORIGIN("origin", d -> d.origin),
COLOR("color", d -> d.color),
QUALITY("quality", d -> d.quality),
COUNTRY("country", d -> d.country),
QUANTITY("quantity", d -> d.quantity),
AVAILABILITY("availability", d -> d.availability),
PRICE("price", d -> d.price);
private String name;
private Function<Detail, Object> valueExtractor;
private DetailQueryParams(String name,
Function<Detail, Object> valueExtractor) {
this.name = name;
this.valueExtractor = valueExtractor;
}
public static Predicate<Detail> mustMatchDetailValues(
Function<String, Optional<String>> queryParamGetter) {
return Arrays.asList(values()).stream()
.map(p -> queryParamGetter.apply(p.name)
.map(q -> (Predicate<Detail>)
d -> String.valueOf(p.valueExtractor.apply(d)).equals(q))
.orElse(d -> true))
.reduce(Predicate::and)
.orElse(d -> true);
}
}
假设您可以通过例如 request.getQueryParam(String name)
来访问查询参数,该方法返回一个 String
值或 null
,那么使用以下代码调用它:
details.stream()
.filter(DetailQueryParams.mustMatchDetailValues(
name -> Optional.ofNullable(request.getQueryParam(name))))
.collect(Collectors.toList())
该方法的基本作用是:
- for each possible query param
- get its value from the request
- if value is present build predicate which
- gets field value from detail object and convert to string
- check that both strings (queried and extracted) matches
- if value is not present return predicate that always returns true
- combine resulting predicates using and
- use always true as fallback (which here never actually happens)
当然,这也可以扩展为根据实际值类型生成谓词,而不是比较字符串,以便通过 "priceMin" 和/或 "priceMax" 请求和处理范围等内容。