一、初识
Predicate是Java提供的重要的函数编程接口之一,作用主要是用于逻辑判断。
首先看看源码:
@FunctionalInterface
public interface Predicate {
boolean test(T t);
default Predicate and(Predicate super T> other) {
Objects.requireNonNull(other);
return (t) -> test(t) && other.test(t);
}
default Predicate negate() {
return (t) -> !test(t);
}
default Predicate or(Predicate super T> other) {
Objects.requireNonNull(other);
return (t) -> test(t) || other.test(t);
}
static Predicate isEqual(Object targetRef) {
return (null == targetRef)
? Objects::isNull
: object -> targetRef.equals(object);
}
}
对函数式编程接口有一定了解的同学可能会疑惑,为啥 有这么多方法,不是说函数式编程接口只有一个方法吗?确实没错,但这个方法只限于没有实现的方法,不包括有实现的方法,自从Java引入了default关键字后,在接口内是可以编写default方法的。
喏,上面不是还有一个static方法?其实想想也是能想得通的,static方法属于类的信息,不属于实例信息,我们平时编码的时候可能不会这么写,但是不代表不可以这么写哦。
二、基础用法
我们现在不必纠结其他方法,把注意力集中在boolean test(T t)方法上。我们先看一段示例代码:
List list = Arrays.asList(1, 2, 3, 4, 6);
List list1 = list.stream()
.filter(num -> num < 5)
.collect(Collectors.toList());
这段代码就是过滤列表中小样5的数字,并生成一个新的列表,当我们点进filter方法的实现,代码如下:
@Override
public final Stream filter(Predicate super P_OUT> predicate) {
Objects.requireNonNull(predicate);
return new StatelessOp(this, StreamShape.REFERENCE,
StreamOpFlag.NOT_SIZED) {
@Override
Sink opWrapSink(int flags, Sink sink) {
return new Sink.ChainedReference(sink) {
@Override
public void begin(long size) {
downstream.begin(-1);
}
@Override
public void accept(P_OUT u) {
if (predicate.test(u))
downstream.accept(u);
}
};
}
};
}
这里我们暂时不要关心其他代码,注意点放在两个地方,一个就是filter的参数列表filter(Predicate super P_OUT> predicate),另一个就是predicate.test(u)。
看到这个两个地方,你或许就明白了我们平时常用的filter方法其实就是依赖Predicate函数接口来完成逻辑判断的。
那我们该如何使用Predicate接口呢?请看用例:
// 逻辑判断工具
public class LogicUtil {
public static boolean qualified(Predicate predicate, Person person) {
return predicate.test(person);
}
}
// 测试代码
public static void main(String[] args) {
List list = Arrays.asList(new Person("小明",180), new Person("小刚", 178));
for (Person person : list) {
if (LogicUtil.qualified(p -> p.getHeight() >= 180, person)) {
System.out.println(person.getName() + "身高合格!");
}
}
}
这里只是举了一很简单的例子,过滤身高大于180的。这里我们将过滤的条件由调用者传入,能够增加编程的灵活性,也就是说逻辑的判断由调用者自行实现。
Predicate使用场景推荐:
在一个公共函数内,大部分逻辑是通用的,但是一小部分判断逻辑是不一样的,可以使用Predicate作为公共函数的入参,将那一小部分判断逻辑通过Lambda表达式的方式传入公共函数。就像上面filter函数的实现一样。
三、高阶用法
既然是接口,那么我们当然可以去实现它啦。如果你的判断逻辑比较复杂,用Lambda表达式比较繁琐或不够整洁时,你可以去实现Predicate接口,如下:
// 实现接口
public class Filter implements Predicate {
@Override
public boolean test(Person person) {
return person.getHeight() >= 180 && Objects.equals(person.getGender(), "man");
}
}
// 工具
public class LogicUtil {
public static boolean qualified3(Predicate filter, Person person) {
return filter.test(person);
}
}
// 测试代码
public static void main(String[] args) {
List list = Arrays.asList(new Person("小明",180, "man"),
new Person("小刚", 178, "man"),
new Person("小红", 190, "woman"));
for (Person person : list) {
if (LogicUtil.qualified3(new Filter(), person)) {
System.out.println(person.getName() + "合格!");
}
}
}
这种用法在抽象设计方面有很大的优势。
四、Predicate的其他方法
文章开头我们就看到Predicate接口内还有and、negate、or、isEqual等方法,下面就简单的介绍一下。
4.1 and
先看看and函数的源码:
default Predicate and(Predicate super T> other) {
Objects.requireNonNull(other);
return (t) -> test(t) && other.test(t);
}
说明:在返回语句中,(t)是lambda表达式的参数,test(t) && other.test(t)是主体。
and函数的功能就是拼接两个Predicate,返回新的Predicate,看看用法:
// 身高过滤器
public class HeightFilter implements Predicate {
@Override
public boolean test(Person person) {
return person.getHeight() >= 180;
}
}
// 性别过滤器
public class GenderFilter implements Predicate {
@Override
public boolean test(Person person) {
return Objects.equals(person.getGender(), "man");
}
}
// 测试代码
public static void main(String[] args) {
List list = Arrays.asList(new Person("小明", 180, "man"),
new Person("小刚", 178, "man"),
new Person("小红", 190, "woman"));
List list1 = list.stream()
.filter(new HeightFilter().and(new GenderFilter()))
.collect(Collectors.toList());
}
4.2 negate
先看看negate函数源码:
default Predicate negate() {
return (t) -> !test(t);
}
函数很简单,就是返回predicate的否定。
用法:
// 身高过滤器
public class HeightFilter implements Predicate {
@Override
public boolean test(Person person) {
return person.getHeight() >= 180;
}
}
// 测试代码
public static void main(String[] args) {
List list = Arrays.asList(new Person("小明", 180, "man"),
new Person("小刚", 178, "man"),
new Person("小红", 190, "woman"));
List list1 = list.stream()
.filter(new HeightFilter().negate())
.collect(Collectors.toList());
}
就是返回所有身高小于180的数据人。
4.3 or
default Predicate or(Predicate super T> other) {
Objects.requireNonNull(other);
return (t) -> test(t) || other.test(t);
}
学完and函数,理解or就没啥问题了,简单说,就是满足众多条件中一个一个即可:
// 身高过滤器
public class HeightFilter implements Predicate {
@Override
public boolean test(Person person) {
return person.getHeight() >= 180;
}
}
// 性别过滤器
public class GenderFilter implements Predicate {
@Override
public boolean test(Person person) {
return Objects.equals(person.getGender(), "woman");
}
}
// 测试代码
public static void main(String[] args) {
List list = Arrays.asList(new Person("小明", 180, "man"),
new Person("小刚", 178, "man"),
new Person("小红", 160, "woman"));
List list1 = list.stream()
.filter(new HeightFilter().or(new GenderFilter()))
.collect(Collectors.toList());
}
此时,小明、小红都满足条件
4.4 isEqual
再来看看最后一个静态方法:
static Predicate isEqual(Object targetRef) {
return (null == targetRef)
? Objects::isNull
: object -> targetRef.equals(object);
}
咋一看,有的小伙伴可能不是很理解,其实拆分一下也不难。
首先很容易看出里面是一个三目运算符;
其次Objects::isNull就是lambda表达式的一种简化写法,还原就是如下语句:
object -> Objects.isNull(object)
即:当targetRef=null时,Objects.isNull(object)的结果就是Predicate的结果
否则,返回object -> targetRef.equals(object)
用法:
// 测试代码
public static void main(String[] args) {
Person xiaoming = new Person("小明", 180, "man");
List list = Arrays.asList(xiaoming,
new Person("小刚", 178, "man"),
new Person("小红", 160, "woman"));
List list1 = list.stream()
.filter(Predicate.isEqual(xiaoming))
.collect(Collectors.toList());
}
五、Predicate的其他变体
接口名
参数
返回类型
描述
BiPredicate
(T, U)
boolean
接受两个参数
DoublePredicate
double
boolean
接受double类型参数
IntPredicate
int
boolean
接受int类型参数
LongPredicate
long
boolean
接受long类型参数
好了,有关Predicate接口的介绍到此为止,(づ ̄3 ̄)づ╭❤~
如果觉得《predicate java 作用_Java函数式编程接口详解之Predicate》对你有帮助,请点赞、收藏,并留下你的观点哦!