Java 函数式接口

141 阅读4分钟

函数式接口

函数式接口定义

函数式接口:有且仅有一个抽象方法,可以有多个非抽象方法的接口。

Java为函数式接口引入了一个注解@FunctionalInterface,主要用于编译级错误检查,加上该注解,当接口不符合函数式接口定义的时候,编译器会报错。

@FunctionalInterface是一个可选注解,就算不写这个注解,只要保证满足接口只有一个抽象方法,也照样是函数式接口,但是,建议加上该注解。

自定义函数式接口样例:

@FunctionalInterface
public interface MyFunctionInterface {

    void duRun();
}

public class Main {
    public void run(MyFunctionInterface myFunctionInterface){
        myFunctionInterface.duRun();
    }
    public static void main(String[] args) {
        Main main = new Main();
        main.run(() -> System.out.println("run myFunctionInterface"));
    }
}

函数式接口使用场景

1. 函数式接口作为方法的参数

如果方法的参数是一个函数式接口,我们可以用Lambda表达式作为参数传递,上述的例子正是将函数式接口作为方法的参数使用。再例如线程中的Runnable接口:

public class Main {
    // 函数式接口作为方法的参数
    public void run(Runnable runnable) {
        new Thread(runnable).start();
    }

    public static void main(String[] args) {
        Main main = new Main();
        main.run(() -> System.out.println("do runnable"));
    }
}

2. 函数式接口作为方法的返回值

如果一个方法的返回值是一个函数式接口,我们可以把一个Lambda表达式作为结果返回

@FunctionalInterface
public interface MyFunctionInterface {

    void duRun(int a, int b);
}

public class Main {
    // 函数式接口作为方法的返回值
    public MyFunctionInterface run() {
        return (a, b) -> System.out.println("a-b = " + (a - b));
    }
    
    public static void main(String[] args) {
        Main main = new Main();
        MyFunctionInterface functionInterface = main.run();
        // 执行函数式接口
        functionInterface.duRun(5, 3);
    }
}

常用的函数式接口

常用的函数式接口主要分为四类:

  • Supplier接口:生产者,不接收参数,返回对应的数据
  • Consumer接口:消费者,接收参数,不返回数据
  • Predicate接口:对给定的输入参数执行操作,返回一个boolean类型的结果
  • Function接口:接收参数并执行对应逻辑,返回逻辑执行完之后的结果

Supplier接口

定义

Supplier只有一个get()方法,不接收参数,返回一个符合预期类型的数据

@FunctionalInterface
public interface Supplier<T> {

    /**
     * Gets a result.
     *
     * @return a result
     */
    T get();
}

使用

使用supplier实现简单的工厂:

public class Main {
    public static void main(String[] args) {
        Supplier<Main> supplier = () -> new Main();
        System.out.println(supplier.get());
        System.out.println(supplier.get());
    }
}

Consumer接口

定义

Consumer接口的accept()方法消费一个指定类型的数据,andThen()方法则可以串联多个consumer接口

@FunctionalInterface
public interface Consumer<T> {

    /**
     * Performs this operation on the given argument.
     *
     * @param t the input argument
     */
    void accept(T t);

    // 可连续执行多个Consumer的accept()
    default Consumer<T> andThen(Consumer<? super T> after) {
        Objects.requireNonNull(after);
        return (T t) -> { accept(t); after.accept(t); };
    }
}

使用

输出结果和上面的Supplier使用样例一样,但Consumer通过accept()封装了重复的逻辑:

public class Main {
    public static void main(String[] args) {
        Consumer<Main> consumer = (main) -> System.out.println(main);
        consumer.accept(new Main());
        consumer.accept(new Main());
    }
}

通过andThen将两个Consumer串联,先执行consumer1再执行consumer2:

public class Main {
    public static void main(String[] args) {
        Consumer<Main> consumer1 = (main) -> System.out.println(main);
        Consumer<Main> consumer2 = (main) -> System.out.println(main.hashCode());
        consumer1.andThen(consumer2).accept(new Main());
        consumer1.andThen(consumer2).accept(new Main());
    }
}

Predicate接口

定义

Predicate接口通过test()接口进行判断,并返回Boolean值,Predicate接口还支持取反,比较,组合判断等

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

    // 与组合判断
    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);
    }
}

使用

通过Predict接口判断对象是否为null,且nagate()方法可取反:

public class Main {
    public static void main(String[] args) {
        Predicate<Main> predicate = (main) -> main != null;
        System.out.println(predicate.test(new Main()));
        System.out.println(predicate.test(null));
        System.out.println(predicate.negate().test(null))
    }
}

通过and和or组合判断:

public static void main(String[] args) {
    Predicate<Main> predicate1 = (main) -> main != null;
    Predicate<Main> predicate2 = (main) -> main.getClass().isAssignableFrom(Main.class);
    Predicate<Main> predicate3 = (main) -> main.getClass().isAssignableFrom(MyFunctionInterface.class);
    System.out.println(predicate1.and(predicate2).or(predicate3).test(new Main()));
}

Function接口

定义

Function接口的apply()方法可以根据一个类型的数据得到另一个类型的数据,andThen则也可以

@FunctionalInterface
public interface Function<T, R> {

    /**
     * Applies this function to the given argument.
     *
     * @param t the function argument
     * @return the function result
     */
    R apply(T t);

    // 组合函数,先应用before函数
    default <V> Function<V, R> compose(Function<? super V, ? extends T> before) {
        Objects.requireNonNull(before);
        return (V v) -> apply(before.apply(v));
    }

    // 组合函数,后应用after函数
    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;
    }
}

使用

使用compose,andThen组合三个函数:

public class Main {
    public static void main(String[] args) {
        Function<List<String>, List<String>> function = (list) -> {
            list.add("function");
            return list;
        };
        Function<List<String>, List<String>> before = (list) -> {
            list.add("before");
            return list;
        };
        Function<List<String>, List<String>> after = (list) -> {
            list.add("after");
            return list;
        };
        // 输出[before, function, after]
        System.out.println(function.compose(before).andThen(after).apply(new ArrayList<>()));
    }
}