本文介绍多种方式实现谓词链接。
我们先从一个简单示例开始,如何实用简单谓词过滤集合:
@Test
public void whenFilterList_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")
那么如何实现多个谓词组合条件过滤?
最简单方法时直接链接调用:
@Test
public void whenFilterListWithMultipleFilters_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的名称,我们实用两个filter,每个过滤实用谓词作为条件。
我们可以修改上节示例,使用单个带复杂谓词参数的过滤器:
@Test
public void whenFilterListWithComplexPredicate_thenSuccess(){
List result = names.stream()
.filter(name -> name.startsWith("A") && name.length() < 5)
.collect(Collectors.toList());
assertEquals(1, result.size());
assertThat(result, contains("Adam"));
}
这种方式更灵活,可以使用位操作符构建复杂的谓词逻辑。
如果我们不想使用位操作符构建复杂的谓词条件,Java 8 Predicate提供了有用的方法可以组合谓词。常用的方法包括Predicate.and(), Predicate.or(), and Predicate.negate()
。
下面示例首先定义两个谓词,然后使用and方法进行组合:
@Test
public void whenFilterListWithCombinedPredicatesUsingAnd_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"));
}
我们看到语法相对直接,方法名表明了操作的类型。通过使用and(),我们实现了对列表过滤,仅返回满足两个条件的名称。
我们也可以使用or方法组合谓词,下面示例同时返回以字母J开头或长度小于4的名称:
@Test
public void whenFilterListWithCombinedPredicatesUsingOr_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"));
}
还有Predicate.negate()方法用于组合谓词:
@Test
public void whenFilterListWithCombinedPredicatesUsingOrAndNegate_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的名称集合。
我们并不需要显示定义谓词才能组合,可以直接通过lambda表达式实现:
@Test
public void whenFilterListWithCombinedPredicatesInline_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"));
}
最后我们看看如何链接谓词集合。下面示例中定义了谓词集合,然后通过reduce方法进行组合,符合条件使用and进行链接:
@Test
public void whenFilterListWithCollectionOfPredicatesUsingAnd_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
。
但如果使用or()方法将它们组合在一起,情况就不同了:
@Test
public void whenFilterListWithCollectionOfPredicatesUsingOr_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"));
}
本文我们介绍了Java 8 中不同方式实现多谓词组合过滤,可以在filter方法中使用复杂谓词或组合谓词。