Java 8 Predicate Chain – Java 8 谓词链

最后修改: 2018年 12月 20日

中文/混合/英文(键盘快捷键:t)

1. Overview

1.概述

In this quick tutorial, we’ll discuss different ways to chain Predicates in Java 8.

在这个快速教程中,我们将讨论在Java 8中连锁Predicates的不同方法。

2. Basic Example

2.基本实例

First, let’s see how to use a simple Predicate to filter a List of names:

首先,让我们看看如何使用一个简单的Predicate来过滤一个List的名字。

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

In this example, we filtered our List of names to only leave names that start with “A” using the Predicate:

在这个例子中,我们用Predicate过滤了我们的List的名字,只留下以 “A “开头的名字。

name -> name.startsWith("A")

But what if we wanted to apply multiple Predicates?

但如果我们想应用多个Predicates呢?

3. Multiple Filters

3.多种过滤器

If we wanted to apply multiple Predicates, one option is to simply chain multiple filters:

如果我们想应用多个Predicates一种选择是简单地连锁多个过滤器:

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

We’ve now updated our example to filter our list by extracting names that start with “A” and have a length that is less than 5.

我们现在更新了我们的例子,通过提取以 “A “开头且长度小于5的名字来过滤我们的列表。

We used two filters — one for each Predicate.

我们使用了两个过滤器–每个Predicate一个。

4. Complex Predicate

4.复杂的谓词

Now, instead of using multiple filters, we can use one filter with a complex Predicate:

现在,我们可以使用一个带有复杂谓词的过滤器,而不是使用多个过滤器,

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

This option is more flexible than the first one, as we can use bitwise operations to build the Predicate as complex as we want.

这个选项比第一个选项更灵活,因为我们可以使用位操作来构建Predicate我们想怎么复杂就怎么复杂。

5. Combining Predicates

5.结合谓词

Next, if we don’t want to build a complex Predicate using bitwise operations, Java 8 Predicate has useful methods that we can use to combine Predicates.

接下来,如果我们不想使用位操作建立一个复杂的Predicate,Java 8 Predicate有一些有用的方法,我们可以用来组合Predicate

We’ll combine Predicates using the methods Predicate.and(), Predicate.or(), and Predicate.negate().

我们将使用Predicate.and()Predicate.or()Predicate.negate()等方法组合Predicates

5.1. Predicate.and()

5.1.Predicate.and()

In this example, we’ll define our Predicates explicitly, and then we’ll combine them using Predicate.and():

在这个例子中,我们将明确地定义我们的Predicates,然后我们将使用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"));
}

As we can see, the syntax is fairly intuitive, and the method names suggest the type of operation. Using and(), we’ve filtered our List by extracting only names that fulfill both conditions.

正如我们所看到的,语法是相当直观的,而且方法的名称表明了操作的类型。通过使用and(),我们只提取了满足两个条件的名字,从而过滤了我们的List

5.2. Predicate.or()

5.2.Predicate.or()

We can also use Predicate.or() to combine Predicates.

我们还可以使用Predicate.or()来组合Predicates.

Let’s extract names start with “J”, as well as names with a length that’s less than 4:

让我们提取以 “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"));
}

5.3. Predicate.negate()

5.3.Predicate.negate()

We can use Predicate.negate() when combining our Predicates as well:

在组合我们的Predicate时,我们也可以使用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"));
}

Here, we’ve used a combination of or() and negate() to filter the List by names that start with “J” or have a length that isn’t less than 4.

在这里,我们使用了or()negate()的组合来过滤List中以 “J “开头或长度不小于4的名字。

5.4. Combine Predicates Inline

5.4.结合谓词内联

We don’t need to explicitly define our Predicates to use and(),  or(), and negate().

我们不需要明确定义我们的谓词来使用and()、or()negate()。

We can also use them inline by casting the Predicate:

我们也可以通过铸造Predicate来内联使用它们。

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

6. Combining a Collection of Predicates

6.组合一个谓词的集合

Finally, let’s see how to chain a collection of Predicates by reducing them.

最后,让我们看看如何通过还原来连锁一个谓词的集合。

In the following example, we have a List of Predicates that we combined using Predicate.and():

在下面的例子中,我们有一个ListPredicates,我们使用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"));
}

Note that we use our base identity as:

请注意,我们使用我们的基本身份为。

x->true

But that will be different if we want to combine them using Predicate.or():

但如果我们想用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"));
}

7. Conclusion

7.结论

In this article, we explored different ways to chain Predicates in Java 8, by using filter(), building complex Predicates, and combining Predicates.

在这篇文章中,我们通过使用filter()、构建复杂的Predicates以及组合Predicates>,探讨了在Java 8中链式Predicates的不同方法。

The full source code is available over on GitHub.

完整的源代码可在GitHub上获得