如何解决如何使用Java搜索列表中的多个字段 我尝试了什么问题
我有以下对象的列表:
public class OptionDetailResponse {
private long id;
private String flavor;
private String size;
private String status;
private String barcode;
}
我想根据所有 4 个字段(id
除外)在这些对象的列表中进行搜索:
-
flavor
(来自组合框的输入) -
size
(来自组合框的输入) -
status
(来自组合框的输入) -
barcode
(从文本字段输入)
这是我的 UI,有 4 个输入字段:
我尝试了什么
我尝试使用 Predicate<OptionDetailResponse>
进行搜索:
Predicate<OptionDetailResponse> selectFlavor = e -> e.getParentName().equals(flavor);
Predicate<OptionDetailResponse> selectSize = e -> e.getName().equals(size);
Predicate<OptionDetailResponse> selectStatus = e -> e.getStatus().equals(status);
Predicate<OptionDetailResponse> inputBarcode = e -> e.getBarcode().contains(barcode);
List<OptionDetailResponse> list = responseList.stream().filter(
selectFlavor.and(selectSize).and(selectStatus).and(inputBarcode))
.collect(Collectors.<OptionDetailResponse>toList());
但是当在所有搜索字段中选择一个值时,列表只返回正确的结果。
问题
- 当所有字段都为空时,如何使用 Predicate 获得所有列表?
- 还有其他方法可以按多个字段进行搜索吗?
解决方法
我认为您可以检查可空性或不应该在每个谓词中检查的特定值,具体取决于您在未选择字段中的值。我认为它看起来像这样:
Predicate<OptionDetailResponse> selectFlavor = e -> flavor == null || e.getParentName().equals(flavor);
或
Predicate<OptionDetailResponse> selectFlavor = e -> flavor.equals("your unselected flavor value") || e.getParentName().equals(flavor);
.. 其他谓词也一样。
,请记住,当您在 filter
方法中使用谓词时,结果将是与所提供谓词的“测试”操作匹配的元素列表。
您所做的是在逻辑 AND 中创建一个谓词链。这意味着过滤器的结果将是匹配所有给定谓词的元素列表。
如果您需要不同的结果,您可以通过使用特定的 Predicate 函数来创建您的链,从而最终实现更复杂的条件。
除了 and(Predicate<> target)
,例如您有以下方法:
-
or(Predicate<> target)
:两个谓词之间的短路逻辑或 -
negate()
:谓词当前实例的逻辑否定 -
not(Predicate<> target)
:返回一个谓词,它是所提供谓词的否定
可能您想在每个字段上使用以下过滤器:
- 如果搜索参数未由 UI 提供(或留空),则不应用谓词:意味着谓词匹配所有对象,无论对象的字段值如何
- 如果搜索参数由 UI 提供(或不为空),则应用谓词
也就是说,您可以在流中使用过滤器组合所有已填充的输入字段:
// renamed your stream-result variable to indicate that it was filtered
List<OptionDetailResponse> filteredResult = responseList.stream()
.filter( buildPredicateFromInputFields(flavor,size,status,barcode) )
.collect(Collectors.toList());
作为参数传递给 filter
的谓词由 4 个字段组合而成:
// you could name the method more specific: matchesAllNonEmptyInputs
Predicate<OptionDetailResponse> buildPredicateFromInputFields(
String flavor,String size,String status,String barcode
) {
// build a set of field-matchers (predicate) based on given input fields
// null or empty (or blank) fields are excluded from the set
var givenFieldPredicates = new ArrayList<Predicate<OptionDetailResponse>>(4); // max 4 entries
if (flavor != null && !flavor.isBlank()) {
givenFieldPredicates.add(obj -> flavor.equals(obj.flavor))
}
if (size != null && !size.isBlank()) {
givenFieldPredicates.add(obj -> size.equals(obj.size))
}
if (status != null && !status.isBlank()) {
givenFieldPredicates.add(obj -> status.equals(obj.size))
}
// contained (partial match allowed)
if (barcode != null && !barcode.isBlank()) {
// will throw NullPointerException if object has null barcode!
givenFieldPredicates.add(obj -> obj.barcode.contains(barcode))
}
// combined them using AND: each field predicate must match
return givenFieldPredicates.stream().reduce(x -> true,Predicate::and);
}
另见:
- Baeldung 的 Java 教程:Java 8 Predicate Chain,“6. 组合谓词集合”部分
我们可以使用 Function、BiFunction 和方法引用以及一个 pojo 来保持过滤字段列表的方式以构建类似
@Value
public static class Filter<T> {
private Function<OptionDetailResponse,T> getter;
private BiFunction<T,T,Boolean> filter;
public Predicate<OptionDetailResponse> toPredicate(OptionDetailResponse criteria) {
return o -> filter.apply(getter.apply(o),getter.apply(criteria));
}
}
public static List<Filter<?>> filters() {
List<Filter<?>> filterList = new ArrayList<>();
filterList.add(new Filter<>(OptionDetailResponse::getFlavor,Object::equals));
filterList.add(new Filter<>(OptionDetailResponse::getSize,Object::equals));
filterList.add(new Filter<>(OptionDetailResponse::getStatus,Object::equals));
filterList.add(new Filter<>(OptionDetailResponse::getBarcode,String::contains));
return filterList;
}
public static final List<Filter<?>> FILTERS = filters();
public Predicate<OptionDetailResponse> buildPredicate(OptionDetailResponse searchCriteria) {
return FILTERS
.stream()
.filter(f -> f.getGetter().apply(searchCriteria) != null)
.map(f -> f.toPredicate(searchCriteria))
.reduce(o -> true,Predicate::and);
}
public List<OptionDetailResponse> search(List<OptionDetailResponse> responseList,OptionDetailResponse searchCriteria) {
return responseList.stream()
.filter(buildPredicate(searchCriteria))
.collect(Collectors.toList());
}
版权声明:本文内容由互联网用户自发贡献,该文观点与技术仅代表作者本人。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如发现本站有涉嫌侵权/违法违规的内容, 请发送邮件至 dio@foxmail.com 举报,一经查实,本站将立刻删除。