0
点赞
收藏
分享

微信扫一扫

函数式编程 --- Predicate接口使用解析

(目录)

1. 简介

本文介绍Java 8 Predicate使用.

2. 基本用法

怎么使用简单的Predicate来过滤list中的name

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

我们使用 Predicate来筛选以大写字母A开头的姓名。

name -> name.startsWith(A)

image-20231113213305570

那么如果多个条件这么办?

3. 多条件过滤

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

用两个filter传入两个 Predicate分别过滤 【以A开头的】和【姓名长度小于5】的。

image-20231113213320743

image-20231113213332501

4. 复杂条件

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

使用一个 filter 传入复杂的Predicate.

image-20231113213343187

5. 组合使用 Predicate

Predicates可以将 Predicate.and(), Predicate.or() 和 Predicate.negate()组合起来使用

5.1. Predicate.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));
}

两个条件都要满足

image-20231113213351965

5.2. Predicate.or()

满足其中一个即可

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

image-20231113213401075

5.3. 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));
}

image-20231113213411264

5.4. 内联的方式组合使用 _Predicates

@Test
public void whenFilterListWithCombinedPredicatesInline_thenSuccess(){
List result = names.stream()
.filter(((Predicate)name -> name.startsWith(A))
.and(name -> name.length()

6. 组合 Predicates集合

在开始介绍之前,简单介绍下 reduce 函数

`java.util.stream.Stream#reduce(T, java.util.function.BinaryOperator)

源码的注释中给出等价的写法:

     T result = identity;
for (T element : this stream)
result = accumulator.apply(result, element)
return result;

即,第一个参数当做初始值,后续参数和第一个参数进行运算,最终得到结果。

接下来我们看下面 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));
}

注意这里初始条件是 true (如果初始条件为 false ,后续即使都满足,和初始值一起 and ,也没结果)

image-20231113213438345

然后看 reduce 中使用 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));
}

image-20231113213448147

Predicate::or 操作,通常会将初始值设置为 false,因为如果初始值为 true 不管后续条件是否为 true 最终结果都为 true。

7. 结论

本文介绍Java 8 Predicate。介绍了 Predicate在Stream的filter函数中的运用。讲述了复杂的Predicate或者Predicate的组合的用法。

英文原文:https://www.baeldung.com/java-predicate-chain

一、基本方法使用

1.1、test(T t) 方法:

test方法主要用于参数符不符合规则。返回值 boolean

写法如下:

 Predicate fourLetterLong1 = new Predicate() {
@Override
public boolean test(String s) {
return s.length()>4 ?true:false ;
}
};

配合Lambda filter 使用如下:

public static void main(String[] args) {
List names = Arrays.asList(Java, Scala, C++, Haskell, Lisp,Hell,opt);
Predicate<String> fourLetterLong1 = new Predicate<String>() {
@Override
public boolean test(String s) {
return s.length()>4 ? true : false ;
}
};
names.stream()
.filter(fourLetterLong1)
.forEach((n) -> System.out.println(this is: + n));
}

1.2 、and(Predicate other)

 default Predicate and(Predicate other) {
Objects.requireNonNull(other);
return (t) -> test(t) && other.test(t);
}

add 方法等同于我们的逻辑与&&,存在短路特性,需要所有条件都满足

配合Lambda filter 使用如下:

public static void main(String[] args) {
List names = Arrays.asList(Java, Scala, C++, Haskell, Lisp, Hell, opt);

Predicate fourLetterLong1 = new Predicate() {
@Override
public boolean test(String s) {
return s.length() > 4 ? true : false;
}
};

Predicate startsWith = new Predicate() {
@Override
public boolean test(String s) {
return s.equals(Haskell) ? true : false;
}
};

names.stream()
.filter(fourLetterLong1.and(startsWith))
.forEach((n) -> System.out.println(this is: + n));
}

1.3 、or(Predicate other)

default Predicate or(Predicate other) {
Objects.requireNonNull(other);
return (t) -> test(t) || other.test(t);
}

or 等同于我们的逻辑或 || ,多个条件只要一个满足即可

配合Lambda filter 使用如下:

 public static void main(String[] args) {
List names = Arrays.asList(Java, Scala, C++, Haskell, Lisp, Hell, opt);

Predicate fourLetterLong1 = new Predicate() {
@Override
public boolean test(String s) {
return s.length() > 4 ? true : false;
}
};

Predicate startsWith = new Predicate() {
@Override
public boolean test(String s) {
return s.equals(zzz) ? true : false;
}
};

names.stream()
.filter(fourLetterLong1.or(startsWith))
.forEach((n) -> System.out.println(this is: + n));
}

1.4、negate()方法

negate等同于我们的逻辑非 !

配合Lambda filter 使用如下:

 public static void main(String[] args) {
List names = Arrays.asList(Java, Scala, C++, Haskell, Lisp, Hell, opt);

Predicate fourLetterLong1 = new Predicate() {
@Override
public boolean test(String s) {
return s.length() > 4 ? true : false;
}
};

names.stream()
.filter(fourLetterLong1.negate())
.forEach((n) -> System.out.println(this is: + n));
}

1.5、isEqual(Object targetRef)方法

static  Predicate isEqual(Object targetRef) {
return (null == targetRef)
? Objects::isNull
: object -> targetRef.equals(object);
}

isEqual 类似于equals()区别在于:先判断对象是否为NULL,不为Null的话再使用equals()方法进行比较

配合Lambda filter 使用如下:

public static void main(String[] args) {
List names = Arrays.asList(Java, Scala, C++, Haskell, Lisp, Hell, opt);

Predicate isEqual = new Predicate() {
@Override
public boolean test(String s) {
return Predicate.isEqual(Java).test(s) ? true : false;
}
};
names.stream()
.filter(isEqual)
.forEach((n) -> System.out.println(this is: + n));
}

二、扩展

使用Lambda 新特性和String类中的方法 多条查询

public static void main(String[] args) {
List names = Arrays.asList(Java, Scala, C++, Haskell, Lisp, Hell, opt);
//长度为7
Predicate<String> length = (n) -> n.length() == 4;
// endsWith 方法字符串是否以指定的前缀开头。
Predicate<String> startsWith = (n) -> n.startsWith(J);
// endsWith 字符串是否以指定的后缀结尾。
Predicate<String> endsWith = (n) -> n.endsWith(a);
Predicate<String> isEqual = (n) ->Predicate.isEqual(Haskell).test(n);
names.stream()
.filter(length.and(startsWith).and(endsWith).or(isEqual))
.forEach((n) -> System.out.println(this is: + n));
}
举报

相关推荐

0 条评论