在本快速教程中,我们将讨论在Java 8中谓词链Predicates的不同方法。
让我们看看如何使用简单的谓词来过滤名称列表:
@Test public void whenFilterList_thenSuccess(){ List<String> names = Arrays.asList("Adam", "Alexander", "John", "Tom"); List<String> 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<String> result = names.stream() .filter(name -> name.startsWith("A")) .filter(name -> name.length() < 5) .collect(Collectors.toList()); assertEquals(1, result.size()); assertThat(result, contains("Adam")); }
|
复杂的谓词
我们可以使用一个带有复杂谓词的过滤器,而不是使用多个过滤器:
@Test public void whenFilterListWithComplexPredicate_thenSuccess(){ List<String> 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()和Predicate.negate()方法组合谓词。
我们将明确定义我们的谓词,然后我们将使用Predicate.and()组合它们 :
@Test public void whenFilterListWithCombinedPredicatesUsingAnd_thenSuccess(){ Predicate<String> predicate1 = str -> str.startsWith("A"); Predicate<String> predicate2 = str -> str.length() < 5; List<String> result = names.stream() .filter(predicate1.and(predicate2)) .collect(Collectors.toList()); assertEquals(1, result.size()); assertThat(result, contains("Adam")); }
|
我们可以看到,语法非常直观,方法名称表明了操作的类型, 我们也可以使用 Predicate.or()来组合Predicates。
让我们提取名称以“J”开头,以及长度小于4的名称:
@Test public void whenFilterListWithCombinedPredicatesUsingOr_thenSuccess(){ Predicate<String> predicate1 = str -> str.startsWith("J"); Predicate<String> predicate2 = str -> str.length() < 4; List<String> result = names.stream() .filter(predicate1.or(predicate2)) .collect(Collectors.toList()); assertEquals(2, result.size()); assertThat(result, contains("John","Tom")); }
|
在组合我们的Predicates时我们也可以使用Predicate.negate():
@Test public void whenFilterListWithCombinedPredicatesUsingOrAndNegate_thenSuccess(){ Predicate<String> predicate1 = str -> str.startsWith("J"); Predicate<String> predicate2 = str -> str.length() < 4; List<String> 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。
结合谓词内联
我们不需要明确定义 Predicates要使用and(), or(), 和negate().
可以通过强制Cast谓词来内联它们 :
@Test public void whenFilterListWithCombinedPredicatesInline_thenSuccess(){ List<String> result = names.stream() .filter(((Predicate<String>)name -> name.startsWith("A")) .and(name -> name.length()<5)) .collect(Collectors.toList()); assertEquals(1, result.size()); assertThat(result, contains("Adam")); }
|
结合一组谓词
最后,让我们看看如何通过Reducing合并它们来链接一组Predicates。
在下面的例子中,我们有一个列表的谓词,我们使用组合Predicate.and():
@Test public void whenFilterListWithCollectionOfPredicatesUsingAnd_thenSuccess(){ List<Predicate<String>> allPredicates = new ArrayList<Predicate<String>>(); allPredicates.add(str -> str.startsWith("A")); allPredicates.add(str -> str.contains("d")); allPredicates.add(str -> str.length() > 4); List<String> 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()组合它们会有所不同:
@Test public void whenFilterListWithCollectionOfPredicatesUsingOr_thenSuccess(){ List<String> result = names.stream() .filter(allPredicates.stream().reduce(x->false, Predicate::or)) .collect(Collectors.toList()); assertEquals(2, result.size()); assertThat(result, contains("Adam","Alexander")); }
|
完整的源代码可以在GitHub上获得