使用Java lambda的外部可配置过滤

时间:2017-05-15 13:48:48

标签: java lambda filter java-8 java-stream

假设我有一个外部JSON:

[{
    "condition": "equals",
    "field": "name",
    "value": "jack"
  },
  {
    "condition": "greater",
    "field": "age",
    "value": 25
  }
]

这意味着我想在名为"jack"age > 25的人员的Person对象列表中查看。使用Java 8过滤相当简单(显示的示例仅在名称上过滤)。

但是,我想让这个过滤器可配置,并且还应用多个过滤器。假设下面的Person pojo(这是不言自明的),取名字和年龄,我怎样才能使过滤器动态或可配置?

public class Person {
    private String name;
    private int age;

    public Person(String name, int age) {
        this.name = name;
        this.age = age;
    }

    // Accessors and Mutators
}
List<Person> persons = Arrays.asList(
    new Person("mkyong", 30),
    new Person("jack", 20),
    new Person("lawrence", 40)
);

Person result1 = persons.stream()            // Convert to steam
    .filter(x -> "jack".equals(x.getName())) // we want "jack" only
    .findAny()                               // If 'findAny' then return found
    .orElse(null);  

我期待一个符合条件的Person对象列表作为结果。

2 个答案:

答案 0 :(得分:6)

就我所知,这与streams本身没什么关系。该过滤方法只是一个Predicate,可以作为实例提供,例如从您可以创建的工厂方法中提供。

static Predicate<Person> fromName(String value){
    return p -> p.getName().equals(value);
}

假设您有另一种方法:

static Predicate<Person> fromAge(int value) {
    return p -> p.getAge() == value;
}

由于存在Predicate.andPredicate.or,您可以这样做:

 fromAge(12).and(fromName("jack"));

因此链接你的谓词

答案 1 :(得分:2)

这有两种方法。

您可以直接串联调用所需的过滤器:

Person result1 = persons.stream()
    .filter(x -> "jack".equals(x.getName()))
    .filter(x -> 25 > x.getAge()) // new filter
    .findAny()
    .orElse(null);

或者,您有自己的类实现Predicate<Person>

在这种情况下,您可以使用构建器模式逐步构建谓词。

您必须面对的困难如下:

  • 处理术语(&& vs ||
  • 之间的布尔关系
  • 处理嵌套的布尔关系((a && b) || c不是a && (b || c)

请注意,Predicate有方便的andor方法来链接谓词。