从零单排Java 8(1) —— Predicate使用介绍

1,366 阅读3分钟

简介

image.png

在接下来的阶段中,将和大家分享Java 8 系列的一些知识点。本文和大家讲述Predicate的使用方法介绍以及其背景。

简单示例

首先,让我们看看如何使用简单的filter()来过滤一个List集合:

@Test
public void whenFilterList(){
   List<String> names = Arrays.asList("Apps", "Alibaba", "william", "Son");
   List<String> result = names.stream()
     .filter(name -> name.startsWith("A"))
     .collect(Collectors.toList());
    
   assertEquals(2, result.size());
   assertThat(result, contains("Apps","Alibaba"));
}

在此示例中,我们过滤了List集合,保留以“A”开头的数据 :

name -> name.startsWith("A")

但是假如需要过滤多个条件的话,应该如何?

多个过滤条件

如果我们想要应用多个过滤,一个比较简单地方式就是设置多个过滤器:

@Test
public void whenFilterListWithMultiple(){
    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("Apps"));
}

看上面的示例,通过提取以“A”开头并且长度小于5的数据来过滤我们的集合。

我们使用了两个过滤条件。

改进版本

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

@Test
public void whenFilterListWithComplexPredicate(){
    List<String> result = names.stream()
      .filter(name -> name.startsWith("A") && name.length() < 5)
      .collect(Collectors.toList());
 
    assertEquals(1, result.size());
    assertThat(result, contains("Adam"));
}

这个改进比第一个更灵活,因为我们可以使用按位运算来构建我们想要的复杂语句。

组合Predicates

接下来,如果我们不想使用按位运算构建复杂语句,Java 8 Predicate可以使用有用的方法来组合过滤条件。

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

Predicate.and()

我们来看看只用 and()的方式,可以怎么用


@Test
public void whenFilterListWithCombinedPredicatesUsingAnd(){
    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"));
}

这样的语法非常直观,方法名称表明了操作的类型。使用and(),我们通过仅提取满足两个条件的名称来过滤我们的List。

Predicate.or()

接下来,我们看看or()的方式使用。条件为w开头、或者长度小于4

@Test
public void whenFilterListWithCombinedPredicatesUsingOr(){
    Predicate<String> predicate1 =  str -> str.startsWith("w");
    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"));
}

Predicate.negate()

现在我们来结合一下看看 negate()的使用场景,这个方法是指相反条件,即 <>!xxx


@Test
public void whenFilterListWithCombinedPredicatesUsingOrAndNegate(){
    Predicate<String> predicate1 =  str -> str.startsWith("w");
    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("Apps","Alibaba","william"));
}

上示例的代码中,条件是为 w开头的或者 数据的长度不是小于4的过滤条件。

predicate新写法

我们甚至也可以不用写 and()、or()、negate()就可以使用predicate方法:

@Test
public void whenFilterListWithCombinedPredicatesInline(){
    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("Apps"));
}

复杂的条件组合

最后,让我们看看如何通过编写出一个可以支持多个复杂条件的过滤方法。

在下面的例子中,我们有一个列表集合,我们使用组合Predicate.and() :


@Test
public void whenFilterListWithCollectionOfPredicatesUsingAnd(){
    List<Predicate<String>> allPredicates = new ArrayList<Predicate<String>>();
    allPredicates.add(str -> str.startsWith("A"));
    allPredicates.add(str -> str.contains("ba"));        
    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("Alibaba"));
}

请留意,我们使用了一个关键性代码:

x->true

但是如果我们想要使用Predicate.or()组合它们会有所不同:


@Test
public void whenFilterListWithCollectionOfPredicatesUsingOr(){
    List<String> result = names.stream()
      .filter(allPredicates.stream().reduce(x->false, Predicate::or))
      .collect(Collectors.toList());
     
    assertEquals(2, result.size());
    assertThat(result, contains("Apps","Alibaba"));
}

结论

本文主要是讲解了如何更好的过滤List中的数据,filter()Predicates的使用方法,已经针对的场景。