简介
image.png
在接下来的阶段中,将和大家分享Java 8 系列的一些知识点。本文和大家讲述Predicate的使用方法介绍以及其背景。
简单示例
首先,让我们看看如何使用简单的filter()来过滤一个List集合:
@Test
public void whenFilterList(){
List names = Arrays.asList("Apps", "Alibaba", "william", "Son");
List 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 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 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 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(),我们通过仅提取满足两个条件的名称来过滤我们的List。
Predicate.or()
接下来,我们看看or()的方式使用。条件为w开头、或者长度小于4;
@Test
public void whenFilterListWithCombinedPredicatesUsingOr(){
Predicate predicate1 = str -> str.startsWith("w");
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()
现在我们来结合一下看看 negate()的使用场景,这个方法是指相反条件,即 <>,!xxx。
@Test
public void whenFilterListWithCombinedPredicatesUsingOrAndNegate(){
Predicate predicate1 = str -> str.startsWith("w");
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("Apps","Alibaba","william"));
}
上示例的代码中,条件是为 w开头的或者 数据的长度不是小于4的过滤条件。
predicate新写法
我们甚至也可以不用写 and()、or()、negate()就可以使用predicate方法:
@Test
public void whenFilterListWithCombinedPredicatesInline(){
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("Apps"));
}
复杂的条件组合
最后,让我们看看如何通过编写出一个可以支持多个复杂条件的过滤方法。
在下面的例子中,我们有一个列表集合,我们使用组合Predicate.and() :
@Test
public void whenFilterListWithCollectionOfPredicatesUsingAnd(){
List> allPredicates = new ArrayList>();
allPredicates.add(str -> str.startsWith("A"));
allPredicates.add(str -> str.contains("ba"));
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("Alibaba"));
}
请留意,我们使用了一个关键性代码:
x->true
但是如果我们想要使用Predicate.or()组合它们会有所不同:
@Test
public void whenFilterListWithCollectionOfPredicatesUsingOr(){
List 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的使用方法,已经针对的场景。