什么是函数式接口

2023-11-14 23:03:00 浏览数 (4)

函数式接口是指有且只有一个未实现的方法的接口,一般通过 FunctionalInterface 注解来表示某个接口是个函数式接口。JDK 提供了大量的函数式接口以丰富 Lambda 的典型使用场景,主要在 java.util.function 包中被提供。

先来个例子:

代码语言:txt复制
// 原来的
Consumer c = new Consumer() {
    @Override
    public void accept(Object o) {
        System.out.println(o);
    }
};

// 现在的

Consumer c = (o) -> System.out.println(o);
  • 从上面这段代码,我们能非常直观的感受到函数式的威力,原本几行的代码,一行就结束了,不过简单的背后是默认的公认的规则,下面对其语法规则做一下解释:
  • 在 -> 的前面,也就是 ( ) 部分,是输入的部分,例子里只有一个参数,但实际上是可以有多个的,以 , 分割即可
  • 在 -> 的后边,被 { } 包围的部分就是函数的主体
  • 函数式编程的返回值可有可无,如果有就在最后一句通过 return 进行返回即可
  • 如果函数主体只是单语句的话,{ } 也可以省去。

Java 中的函数式接口

其实在 Java 中,早在 1.8 之前就有函数式接口的,如 Runnable 和 Callable 。而 1.8 呢新增了一个 function 函数接口,它可以理解为一个集合,包含了很多类,用于更好的支持 Java 的函数式编程。调其中的几个来举个例子如下:

Consumer

其代表了接受一个输入参数并且无返回的操作

这个接口中有一个抽象方法 void accept(T t);

用法如下:

代码语言:txt复制
public class Demo{
    public static void main(String[] args) {
        test(s -> System.out.println(s));
    }
 
    private static void consumerString(Consumer<String> function) {
        function.accept("Hello");
    }
}

还有一个默认的方法 andThen

用法如下:

代码语言:txt复制
import java.util.function.Consumer;
 
public class Demo{
    public static void main(String[] args) {
        test(
                // toUpperCase()方法,将字符串转换为大写
                s -> System.out.println(s.toUpperCase()),
                // toLowerCase()方法,将字符串转换为小写
                s -> System.out.println(s.toLowerCase())
        );
    }
 
    private static void test(Consumer<String> one, Consumer<String> two) {
        one.andThen(two).accept("Hello");
    }
}

Function

其代表了接受一个输入参数,返回一个结果。

Function 是另一个函数式编程接口,他代表的含义是就是 “函数”。有输入有输出的一个代码体。其除了 apply 方法外,还有 compose 与 andThen 和 indentity 三个方法。

具体用法如下:

代码语言:txt复制
public static void test() {
    Function<Integer, Integer> f = s -> s  ;
    Function<Integer, Integer> g = s -> s * 2;

    /**
     * 下面表示在执行F时,先执行 g ,并且执行F时使用 g 的输出当作输入。
     * 相当于以下代码:
     * Integer a = g.apply(1);
     * System.out.println(f.apply(a));
     */
    System.out.println(f.compose(g).apply(1));

    /**
     * 表示执行 f 的 Apply 后使用其返回的值当作输入再执行 g 的 Apply;
     * 相当于以下代码
     * Integer a = f.apply(1);
     * System.out.println(g.apply(a));
     */
    System.out.println(f.andThen(g).apply(1));

    /**
     * identity 方法会返回一个不进行任何处理的 Function,即输出与输入值相等; 
     */
    System.out.println(Function.identity().apply("a"));
}

其他还有很多例如 Comparator、Supplier、Operator 等,之后总结 Lambda 遇到了再做细致分析。

总的来讲呢,函数式接口和以往的普通接口最大的不同,就是其支持了行为参数的传递,如传递 Lambda、方法引用、函数式接口对应的实例对象等。但是这种特性的意义并不是必须性的,我个人的理解就是,在关键的时候,用上一笔是最好的。不必为了使用而使用,那样可读性反而就会变成看起来有可读性,实际上更复杂了,因为在原本的语法上,他还嵌套了一层规则用于简化代码,而对于这层规则的转换,也是需要额外开销理解力的。

代码语言:txt复制
System.out.println("compose: "   toInteger.andThen(a -> a   10).andThen(a -> a * 10).compose(ss -> ss   "1").apply("123"));
compose: 12410

根据以上代码的输出结果可知,当有 compose 时,就会先执行它,在从左往右执行 andThen

我正在参与2023腾讯技术创作特训营第三期有奖征文,组队打卡瓜分大奖!

0 人点赞