参考资料:https://www.cnblogs.com/rever/p/9773743.html
今天来学习下 Predicate 断定接口,Predicate是个断言式接口其参数是<T,boolean>,也就是给一个参数T,返回boolean类型的结果。Predicate的具体实现是根据传入的lambda表达式来决定的。
来看源码:
@FunctionalInterface
public interface Predicate<T> {
/**
* Evaluates this predicate on the given argument.
*
* @param t the input argument
* @return {@code true} if the input argument matches the predicate,
* otherwise {@code false}
*/
boolean test(T t);
/**
* Returns a composed predicate that represents a short-circuiting logical
* AND of this predicate and another. When evaluating the composed
* predicate, if this predicate is {@code false}, then the {@code other}
* predicate is not evaluated.
*
* <p>Any exceptions thrown during evaluation of either predicate are relayed
* to the caller; if evaluation of this predicate throws an exception, the
* {@code other} predicate will not be evaluated.
*
* @param other a predicate that will be logically-ANDed with this
* predicate
* @return a composed predicate that represents the short-circuiting logical
* AND of this predicate and the {@code other} predicate
* @throws NullPointerException if other is null
*/
default Predicate<T> and(Predicate<? super T> other) {
Objects.requireNonNull(other);
return (t) -> test(t) && other.test(t);
}
/**
* Returns a predicate that represents the logical negation of this
* predicate.
*
* @return a predicate that represents the logical negation of this
* predicate
*/
default Predicate<T> negate() {
return (t) -> !test(t);
}
/**
* Returns a composed predicate that represents a short-circuiting logical
* OR of this predicate and another. When evaluating the composed
* predicate, if this predicate is {@code true}, then the {@code other}
* predicate is not evaluated.
*
* <p>Any exceptions thrown during evaluation of either predicate are relayed
* to the caller; if evaluation of this predicate throws an exception, the
* {@code other} predicate will not be evaluated.
*
* @param other a predicate that will be logically-ORed with this
* predicate
* @return a composed predicate that represents the short-circuiting logical
* OR of this predicate and the {@code other} predicate
* @throws NullPointerException if other is null
*/
default Predicate<T> or(Predicate<? super T> other) {
Objects.requireNonNull(other);
return (t) -> test(t) || other.test(t);
}
/**
* Returns a predicate that tests if two arguments are equal according
* to {@link Objects#equals(Object, Object)}.
*
* @param <T> the type of arguments to the predicate
* @param targetRef the object reference with which to compare for equality,
* which may be {@code null}
* @return a predicate that tests if two arguments are equal according
* to {@link Objects#equals(Object, Object)}
*/
static <T> Predicate<T> isEqual(Object targetRef) {
return (null == targetRef)
? Objects::isNull
: object -> targetRef.equals(object);
}
}
通过源码可以看到,Predicate默认的方法是test(T t),三个重要的方法 and or negate,对应java中的 && || !。
简单的上一个代码演示下:
@Test
public void first(){
List<Integer> list=new ArrayList<>();
for(int i = 1; i < 20; i++){
list.add(i);
}
Predicate<Integer> p1 = i -> i > 5;
Predicate<Integer> p2 = i -> i<20;
Predicate<Integer> p3 = i -> i%2 == 0;
// 大于5
List lt = list.stream().filter(p1).collect(Collectors.toList());
System.out.println(lt);
// 小于20
lt = list.stream().filter(p2).collect(Collectors.toList());
System.out.println(lt);
// 偶数
lt = list.stream().filter(p3).collect(Collectors.toList());
System.out.println(lt);
// 大于5并且小于20的偶数
lt = list.stream().filter(p1.and(p2).and(p3)).collect(Collectors.toList());
System.out.println(lt.toString());
}
}
我们定义了三个断言p1,p2,p3。现在有一个从1~20的list,我们需要过滤这个list。上述的filter是先单个条件过滤打印,最后一个是组合条件过滤出所有大于5小于20,并且是偶数的列表。结果显示如下:
[6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19]
[1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19]
[2, 4, 6, 8, 10, 12, 14, 16, 18]
[6, 8, 10, 12, 14, 16, 18]
假如突然我们的需求变了,我们现在需要过滤出奇数。那么我不可能直接去改Predicate,因为实际项目中这个条件可能在别的地方也要使用。那么此时我只需要更改filter中Predicate的条件。
// 大于5并且小于20的奇数
lt = list.stream().filter(p1.and(p2).and(p3.negate())).collect(Collectors.toList());
System.out.println(lt.toString());
结果:
[7, 9, 11, 13, 15, 17, 19]
我们直接对p3这个条件取反就可以实现了。是不是很简单?
isEqual这个方法是static类型,返回类型是Predicate,所以我们也可以把它作为函数式接口进行使用。我们可以当做==操作符来使用。
// 大于5等于10
lt = list.stream().filter(p1.and(Predicate.isEqual(10))).collect(Collectors.toList());
System.out.println(lt);
结果:
[10]
Predicate接口还有几个基本类型的扩展,IntPredicate、LongPredicate,收入相应的int long参数,返回类似都是boolean,用法也相同,只是这两个接口都没有static类型的isEqual方法。