前言
Java8的四大函数式接口及相关的扩展接口在日常使用中的频率也是非常多的,包括自己定义的函数式接口,在JDK1.8之前,我们定义的方法都是用来接收参数,然后自己根据参数传递实现逻辑。在1.8之后,可以通过参数传递一段行为代码,将公共的行为代码封装成一个函数式接口传递,可以减少很多代码量,在Stream的API中就有很多的体现,在此归纳总结一下。
函数式接口简介
函数式接口指的是有且只能有一个抽象方法,但是可以有多个非抽象方法的接口,这样的接口可以转换成Lambda表达式。在函数式接口中,可以添加上@FunctionalInterface注解标注这是一个函数式接口,此注解主要用于编译器在编译期检查该接口是否符合函数式接口的定义规范(即只能有一个抽象方法),如不符合,编译器则会报错提示。
四大核心函数式接口
Consumer-消费型接口
源码如下,此接口中的抽象方法则是accept,传入一个T参数,执行自定义逻辑将它消费掉,没有返回值。
@FunctionalInterface
publicinterface Consumer<T> {
void accept(T t);
default Consumer<T> andThen(Consumer<? super T> after) {
Objects.requireNonNull(after);
return (T t) -> { accept(t); after.accept(t); };
}
}
示例,实现一个打印List的Consumer接口,传入不同的List将其打印。
有没有机智的同学发现,示例中的forEach()方法其参数就是一个Consumer接口,根据传入的集合将其遍历。
Consumer接口在JDK中的应用,此为Iterable接口中的forEach方法,ArrayList中的forEach就是重写了该方法。
default void forEach(Consumer<? super T> action) {
Objects.requireNonNull(action);
for (T t : this) {
action.accept(t);
}
}
Supplier-供给型接口
源码如下,此接口中方法只有一个无参的方法,返回一个T类型的结果。
@FunctionalInterface
publicinterface Supplier<T> {
T get();
}
示例,实现一个返回随机数的Supplier接口,通过指定数量返回一个随机数集合。
Supplier接口在JDK中的应用,此为Optional类中的orElseGet方法。
public T orElseGet(Supplier<? extends T> other) {
return value != null ? value : other.get();
}
Function-函数型接口
源码如下,此接口中的抽象方法为apply,传入一个T参数,返回一个R结果。
@FunctionalInterface
publicinterface Function<T, R> {
R apply(T t);
default <V> Function<V, R> compose(Function<? super V, ? extends T> before) {
Objects.requireNonNull(before);
return (V v) -> apply(before.apply(v));
}
default <V> Function<T, V> andThen(Function<? super R, ? extends V> after) {
Objects.requireNonNull(after);
return (T t) -> after.apply(apply(t));
}
static <T> Function<T, T> identity() {
return t -> t;
}
}
示例,将字符串使用MD5加密后返回。
Function接口在JDK中的应用,此为Stream中的map与flatMap方法。
<R> Stream<R> map(Function<? super T, ? extends R> mapper);
<R> Stream<R> flatMap(Function<? super T, ? extends Stream<? extends R>> mapper);
Predicate-断言型接口
源码如下,抽象方法为test,传入一个T类型,返回一个固定类型为布尔值的方法。
@FunctionalInterface
publicinterface Predicate<T> {
boolean test(T t);
default Predicate<T> and(Predicate<? super T> other) {
Objects.requireNonNull(other);
return (t) -> test(t) && other.test(t);
}
default Predicate<T> negate() {
return (t) -> !test(t);
}
default Predicate<T> or(Predicate<? super T> other) {
Objects.requireNonNull(other);
return (t) -> test(t) || other.test(t);
}
static <T> Predicate<T> isEqual(Object targetRef) {
return (null == targetRef)
? Objects::isNull
: object -> targetRef.equals(object);
}
}
示例,判断数字是否大于0。
Predicate接口在JDK中的应用,此为Stream中的filter方法。
Stream<T> filter(Predicate<? super T> predicate);
在StreamAPI中的应用
熟悉使用Stream的靓仔们肯定知道,它极大简化了我们的代码量,在其中就有很多频繁应用函数式接口的地方。
四大函数式接口总结
扩展接口
消费型接口-扩展接口
供给型接口-扩展接口
函数型接口-扩展接口
断言型接口-扩展接口
总结
以上就是四大内置核心函数式接口与各扩展接口的使用,可以涵盖工作中大部分的业务场景。如还有不满足业务场景的地方,hutool工具包中也有更多的扩展接口可使用,也可以自定义函数式接口,结合自身的业务使用,非常灵活强大,配合Lambda表达式和方法引用可以使代码更简洁,省略冗余的代码。
参考链接:
JDK8新特性第二篇:四大函数式接口【Function/Consumer/Supplier/Perdicate】、接口的扩展方法【default/static】