JDK8 四大核心函数式接口及扩展接口总结

时间:2023-02-03 18:07:00

 Java8的四大函数式接口及相关的扩展接口在日常使用中的频率也是非常多的,包括自己定义的函数式接口,在JDK1.8之前,我们定义的方法都是用来接收参数,然后自己根据参数传递实现逻辑。在1.8之后,可以通过参数传递一段行为代码,将公共的行为代码封装成一个函数式接口传递,可以减少很多代码量,在Stream的API中就有很多的体现,在此归纳总结一下。

 

函数式接口简介

函数式接口指的是有且只能有一个抽象方法,但是可以有多个非抽象方法的接口,这样的接口可以转换成Lambda表达式。在函数式接口中,可以添加上@FunctionalInterface注解标注这是一个函数式接口,此注解主要用于编译器在编译期检查该接口是否符合函数式接口的定义规范(即只能有一个抽象方法),如不符合,编译器则会报错提示。

 

四大核心函数式接口

Consumer-消费型接口

源码如下,此接口中的抽象方法则是accept,传入一个T参数,执行自定义逻辑将它消费掉,没有返回值。

@FunctionalInterface
public interface 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将其打印。

JDK8 四大核心函数式接口及扩展接口总结

 

有没有机智的同学发现,示例中的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
public interface Supplier<T> {

    T get();
}

 

示例,实现一个返回随机数的Supplier接口,通过指定数量返回一个随机数集合。

JDK8 四大核心函数式接口及扩展接口总结

 

Supplier接口在JDK中的应用,此为Optional类中的orElseGet方法。

public T orElseGet(Supplier<? extends T> other) {
    return value != null ? value : other.get();
}

 

Function-函数型接口

源码如下,此接口中的抽象方法为apply,传入一个T参数,返回一个R结果。

@FunctionalInterface
public interface 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加密后返回。

JDK8 四大核心函数式接口及扩展接口总结

 

Function接口在JDK中的应用,此为Stream中的mapflatMap方法。

<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
public interface 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。

JDK8 四大核心函数式接口及扩展接口总结

 

Predicate接口在JDK中的应用,此为Stream中的filter方法。

Stream<T> filter(Predicate<? super T> predicate);

 

在StreamAPI中的应用

熟悉使用Stream的靓仔们肯定知道,它极大简化了我们的代码量,在其中就有很多频繁应用函数式接口的地方。

JDK8 四大核心函数式接口及扩展接口总结

 

四大函数式接口总结

JDK8 四大核心函数式接口及扩展接口总结

 

扩展接口

消费型接口-扩展接口

JDK8 四大核心函数式接口及扩展接口总结

 

供给型接口-扩展接口

JDK8 四大核心函数式接口及扩展接口总结

 

函数型接口-扩展接口

JDK8 四大核心函数式接口及扩展接口总结

 

断言型接口-扩展接口

JDK8 四大核心函数式接口及扩展接口总结

 

总结

以上就是四大内置核心函数式接口与各扩展接口的使用,可以涵盖工作中大部分的业务场景。如还有不满足业务场景的地方,hutool工具包中也有更多的扩展接口可使用,也可以自定义函数式接口,结合自身的业务使用,非常灵活强大,配合Lambda表达式和方法引用可以使代码更简洁,省略冗余的代码。

 

参考链接:

Java8新特性 | 四大函数式接口及其扩展接口

JDK8新特性第二篇:四大函数式接口【Function/Consumer/Supplier/Perdicate】、接口的扩展方法【default/static】