1.泛型接口
我们举个例子,以前来看一下JPA定义的写法:
Specification接口为:
public interface Specification{
Predicate toPredicate(Root var1, CriteriaQuery>var2, CriteriaBuilder var3);
}
以前的写法为(定义一个静态内部类实现):
public static Specification searchKeyword(final String key, final Date startTime, finalDate endTime) {return new Specification() {
@Overridepublic Predicate toPredicate(Root root, CriteriaQuery>criteriaQuery, CriteriaBuilder criteriaBuilder) {
List predicates = new ArrayList();if(StringUtils.isNotEmpty(key)) {
predicates.add(criteriaBuilder.or(
criteriaBuilder.like(root.get("description"), "%" + key + "%"),
criteriaBuilder.like(root.get("exceptionMessage"), "%" + key + "%")));
}if (startTime != null && endTime != null){
predicates.add(criteriaBuilder.and(
criteriaBuilder.greaterThan(root.get("createTime"), startTime),
criteriaBuilder.lessThan(root.get("createTime"), endTime)
));
}return criteriaBuilder.and(predicates.toArray(newPredicate[]{}));
}
};
}
1.8以后的写法为:
public static Specification searchKeyword(final String key, finalBoolean isDeleted) {return (root, criteriaQuery, criteriaBuilder) ->{
List predicates = new ArrayList<>();if(StringUtils.isNotEmpty(key)) {
predicates.add(criteriaBuilder.or(
criteriaBuilder.like(root.get("fileName"), "%" + key + "%"),
criteriaBuilder.like(root.get("outputPath"), "%" + key + "%")));
}if (isDeleted != null) {
predicates.add(criteriaBuilder.or(
criteriaBuilder.equal(root.get("isDeleted"), isDeleted)));
}return criteriaBuilder.and(predicates.toArray(newPredicate[]{}));
};
}
2.谓词链(讨论在Java 8中链接Predicates的不同方法):
首先,让我们看看如何使用简单的谓词来过滤名称列表:
@Testpublic voidwhenFilterList_thenSuccess(){
List names = Arrays.asList("Adam", "Alexander", "John", "Tom");
List result =names.stream()
.filter(name-> name.startsWith("A"))
.collect(Collectors.toList());
assertEquals(2, result.size());
assertThat(result, contains("Adam","Alexander"));
}
在这个例子中,我们过滤了名称列表,只使用谓词保留以“A”开头的名称:
name ->name.startsWith("A")
但是,如果我们想要应用多个Predicates呢?
3.多个过滤器
如果我们想要应用多个谓词,一个选项是简单地链接多个过滤器:
@Testpublic voidwhenFilterListWithMultipleFilters_thenSuccess(){
List result =names.stream()
.filter(name-> name.startsWith("A"))
.filter(name-> name.length() < 5)
.collect(Collectors.toList());
assertEquals(1, result.size());
assertThat(result, contains("Adam"));
}
我们现在更新了我们的示例,通过提取以“A”开头并且长度小于5的名称来过滤我们的列表,我们使用了两种过滤修饰-每个谓词。
4.复杂的谓词
现在,我们可以使用一个带有复杂Predicate的过滤器,而不是使用多个过滤器:
@Testpublic voidwhenFilterListWithComplexPredicate_thenSuccess(){
List result =names.stream()
.filter(name-> name.startsWith("A") && name.length() < 5)
.collect(Collectors.toList());
assertEquals(1, result.size());
assertThat(result, contains("Adam"));
}
这个选项比第一个选项更灵活,因为我们可以使用按位运算来构建 我们想要的复杂谓词。
5.结合谓词
接下来,如果我们不想使用按位运算构建复杂的谓词,Java 8 Predicate可以使用有用的方法来组合谓词我们将使用Predicate.and(),Predicate.or()和Predicate.negate()方法组合谓词。
5.1 Predicate.and()
在这个例子中,我们将明确定义我们的谓词,然后我们将使用Predicate.and()组合它们:
@Testpublic voidwhenFilterListWithCombinedPredicatesUsingAnd_thenSuccess(){
Predicate predicate1 = str -> str.startsWith("A");
Predicate predicate2 = str -> str.length() < 5;
List result =names.stream()
.filter(predicate1.and(predicate2))
.collect(Collectors.toList());
assertEquals(1, result.size());
assertThat(result, contains("Adam"));
}
我们可以看到,语法非常直观,方法名称表明了操作的类型。使用Predicate.and(),我们通过仅提取满足两个条件的名称来过滤我们的列表。
5.2 Predicate.or()
我们也可以使用 Predicate.or()来组合Predicates。 让我们提取名称以“J”开头,以及长度小于4的名称:
@Testpublic voidwhenFilterListWithCombinedPredicatesUsingOr_thenSuccess(){
Predicate predicate1 = str -> str.startsWith("J");
Predicate predicate2 = str -> str.length() < 4;
List result =names.stream()
.filter(predicate1.or(predicate2))
.collect(Collectors.toList());
assertEquals(2, result.size());
assertThat(result, contains("John","Tom"));
}
5.3 Predicate.negate()
在组合我们的Predicates时我们也可以使用Predicate.negate():
@Testpublic voidwhenFilterListWithCombinedPredicatesUsingOrAndNegate_thenSuccess(){
Predicate predicate1 = str -> str.startsWith("J");
Predicate predicate2 = str -> str.length() < 4;
List result =names.stream()
.filter(predicate1.or(predicate2.negate()))
.collect(Collectors.toList());
assertEquals(3, result.size());
assertThat(result, contains("Adam","Alexander","John"));
}
在这里,我们使用or()和negate()的组合来按名称以“J”开头或长度不小于4 来过滤List
5.4 结合谓词内联
我们不需要明确定义要使用的谓词and(), or(),以及negate()。 我们也可以通过强制谓词来内联它们:
@Testpublic voidwhenFilterListWithCombinedPredicatesInline_thenSuccess(){
List result =names.stream()
.filter(((Predicate)name -> name.startsWith("A"))
.and(name-> name.length()<5))
.collect(Collectors.toList());
assertEquals(1, result.size());
assertThat(result, contains("Adam"));
}
6.结合一组谓词
最后,让我们看看如何通过减少它们来链接一组Predicates。在下面的例子中,我们有一个列表的谓词,我们使用组合Predicate.and():
@Testpublic voidwhenFilterListWithCollectionOfPredicatesUsingAnd_thenSuccess(){
List> allPredicates = new ArrayList>();
allPredicates.add(str-> str.startsWith("A"));
allPredicates.add(str-> str.contains("d"));
allPredicates.add(str-> str.length() > 4);
List result =names.stream()
.filter(allPredicates.stream().reduce(x->true, Predicate::and))
.collect(Collectors.toList());
assertEquals(1, result.size());
assertThat(result, contains("Alexander"));
}
注意,我们使用基本标识作为:
x->true
但是如果我们想要使用Predicate.or()组合它们会有所不同:
@Testpublic voidwhenFilterListWithCollectionOfPredicatesUsingOr_thenSuccess(){
List result =names.stream()
.filter(allPredicates.stream().reduce(x->false, Predicate::or))
.collect(Collectors.toList());
assertEquals(2, result.size());
assertThat(result, contains("Adam","Alexander"));
}