仅过滤请求中存在的参数

时间:2017-06-06 07:14:08

标签: java java-8 java-stream

有很多关于Java 8 lambda操作的文章,但是到目前为止我找不到我需要的东西。我试图将它们转换为我的方法,不幸的是我无法成功

想象一下,您有POJO中的请求,例如;

public class DummyRequest {

    private String name;
    private String surname;
    private String country;

    public String getName() {
        return name;
    }

    public void setName(String name) {
        this.name = name;
    }

    public String getSurname() {
        return surname;
    }

    public void setSurname(String surname) {
        this.surname = surname;
    }

    public String getCountry() {
        return country;
    }

    public void setCountry(String country) {
        this.country= country;
    }

}

在REST / SOAP请求期间, 姓氏 变量将被指定为 null

List<Person> persons = Arrays.asList(
                new Person("maria", "gambert", "italy"),
                new Person("jack", "johson", "usa"),
                new Person("johnson", "jack", "usa"),
                new Person("kate", "julia", "spain"),
                new Person("jack","bob","uk");

DummyRequest dr = new DummyRequest();
dr.setName("jack");
dr.setCountry("usa");

如果我提前知道surname字段为null,我可以设法过滤此列表,忽略该字段:

List<Person> result4 = persons.stream().
filter(x -> dummyRequest.getName().equals(x.getName())).
filter( x-> dummyRequest.getCountry().equals(x.getCountry())).
collect(Collectors.toList());

但是我不知道哪些字段是null哪个字段不是{{1}}。我怎样才能根据非空请求参数来过滤我的数据?

4 个答案:

答案 0 :(得分:3)

我会为此定义一个静态方法,因为你要多次复制代码:

private static boolean nullableOrEqual(String left, String right) {
    return left == null || left.equals(right);
}

然后用法是:

List<Person> result = persons.stream()
            .filter(x -> nullableOrEqual(dr.getSurname(), x.getSurname()))
            .filter(x -> nullableOrEqual(dr.getCountry(), x.getCountry()))
            .filter(x -> nullableOrEqual(dr.getName(), x.getName()))
            .collect(Collectors.toList());

答案 1 :(得分:3)

如果您只想应用dummyRequest包含非空值的过滤器,则必须动态构建流以获得最有效的解决方案。

这可以通过实现有条件地应用过滤器的辅助方法来轻松完成:

public static <T, V> Stream<T> filterIfNotNull(Stream<T> stream, V filterValue, Function<T, V> property) {
    if (filterValue == null) {
        return stream;
    }

    return stream.filter(t -> filterValue.equals(property.apply(t)));
}

(在您的示例中T始终为PersonV始终为String,但此通用版本允许更多可重用性,而无需在呼叫网站处增加复杂性)

然后可以像这样实现流/收集:

Stream<Person> personStream = persons.stream();
personStream = filterIfNotNull(personStream, dummyRequest.getName(), Person::getName);
personStream = filterIfNotNull(personStream, dummyRequest.getSurname(), Person::getSurname);
personStream = filterIfNotNull(personStream, dummyRequest.getCountry(), Person::getCountry);
List<Person> result4 = personStream.collect(Collectors.toList());

此技术可确保对请求的属性进行空值检查仅应用一次。

答案 2 :(得分:2)

如果您只想使用dummyRequest的非空属性进行过滤,则只需向每个Predicate添加空检查:

List<Person> result4 =
    persons.stream()
           .filter(x -> dummyRequest.getSurname() == null || dummyRequest.getSurname().equals(x.getSurname()))
           .filter(x -> dummyRequest.getName() == null || dummyRequest.getName().equals(x.getName()))
           .filter(x -> dummyRequest.getCountry() == null || dummyRequest.getCountry().equals(x.getCountry()))
           .collect(Collectors.toList());

答案 3 :(得分:0)

您可以创建一个checkNonNullProperties辅助方法,该方法返回Predicate<Person>,仅检查DummyRequest实例的非空属性是否相等。您可以按如下方式使用它:

Predicate<Person> condition = checkNonNullProperties(
    Arrays.asList(
        dr.getCountry(),
        dr.getName(),
        dr.getSurname()),
    Arrays.asList(
        Person::getCountry,
        Person::getName,
        Person::getSurname));

List<Person> result = people.stream()
    .filter(condition)
    .collect(Collectors.toList());

辅助方法:

private static <T> Predicate<T> checkNonNullProperties(
        List<?> values,
        List<Function<T, ?>> extractors) {
    return IntStream.range(0, values.size()).mapToObj(i ->
            (Predicate<T>) t -> {
                Object value = values.get(i);
                Object property = extractors.get(i).apply(t);
                return value == null || value.equals(property);
            })
            .reduce(t -> true, Predicate::and);
}

checkNonNullProperties方法接收用于检查相等性的值列表以及将从返回谓词的参数中提取属性的函数列表。将仅针对那些非空的值检查提取的属性与其对应值的相等性。

我正在使用IntStream来驱动两个列表的迭代。在mapToObj方法中,我将流的int值映射到谓词,该谓词在提供的值为true时或在等于提取的属性时返回null。 / p>

最后,这些谓词通过Predicate::and运算符缩减为最终谓词。在reduce调用中,我为AND运算符提供了身份谓词,即t -> true(始终返回true)。