Java 8 谓词(Predicate)链

Java 8 谓词(Predicate)链

本文介绍多种方式实现谓词链接。

1. 从示例开始

我们先从一个简单示例开始,如何实用简单谓词过滤集合:

@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")

那么如何实现多个谓词组合条件过滤?

2. 多条件过滤

2.1 直接链接调用

最简单方法时直接链接调用:

@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,每个过滤实用谓词作为条件。

2.2 复杂的谓词

我们可以修改上节示例,使用单个带复杂谓词参数的过滤器:

@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"));
}

这种方式更灵活,可以使用位操作符构建复杂的谓词逻辑。

3. 组合谓词

如果我们不想使用位操作符构建复杂的谓词条件,Java 8 Predicate提供了有用的方法可以组合谓词。常用的方法包括Predicate.and(), Predicate.or(), and Predicate.negate()

3.1 Predicate.and()

下面示例首先定义两个谓词,然后使用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(),我们实现了对列表过滤,仅返回满足两个条件的名称。

3.2 Predicate.or()

我们也可以使用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"));
}

3.3 Predicate.negate()

还有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的名称集合。

3.4 通过lambda表达式组合谓词

我们并不需要显示定义谓词才能组合,可以直接通过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"));
}

3.5 组合谓词集合

最后我们看看如何链接谓词集合。下面示例中定义了谓词集合,然后通过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"));

}

4. 总结

本文我们介绍了Java 8 中不同方式实现多谓词组合过滤,可以在filter方法中使用复杂谓词或组合谓词。

你可能感兴趣的:(java8~9核心功能,Predicate)