【Java】JDK 提供的函数式接口

函数式接口就是只定义一个抽象方法的接口。对于所有的函数式接口,我们都可以为它创建一个 Lambda 表达式。

函数式接口

在此简单介绍一下函数式接口。

什么是函数式接口

函数式接口就是只定义一个抽象方法的接口。由于 JDK8 开始提供 default 关键字,因此函数式接口并不仅仅只能定义一个方法,哪怕一个接口有很多默认方法和静态方法,只要只有一个抽象方法,它就是函数式接口。

函数式接口的作用是什么

函数式接口的作用在于,允许 Lambda 表达式以内联的形式作为函数式接口的实现,并把整个表达式作为它自身的实例。也就是说,Lambda 表达式可以作用在任何以函数式接口为方法参数的地方。

例如,Runnable 就是一个函数式接口,因为它里面只有 void run() 这一个抽象方法,因此可以将 Lambda 表达式作用在以 Runnable 为参数的地方。由于 Thread 的构造方法其中一个是 Thread(Runnable runnable),所以可以这样:

new Thread(() -> System.out.println("HELLO WORLD")).start();
复制代码

函数描述符

使用一个 Lambda 表达式作为函数式接口的实现时,函数式接口的抽象方法的签名就是 Lambda 表达式的签名。这个抽象方法就叫做函数描述符

方法签名就是 java 中的方法签名的概念,用于判断同一个类中方法的唯一性,由方法名称、方法参数类型和方法参数数量构成。而对于函数式接口而言,由于规定只能拥有一个抽象方法,以此来表示 Lambda 表达式,因此方法名称这一属性忽略。

注意将函数描述符与方法描述符做区分,方法描述符是 JVM 里的概念,用于描述一个方法的属性,包括方法的参数数量、参数类型和返回值。如 (Ljava/lang/StringI)V

为什么要创造函数式接口?

Java 的设计者当初也曾想过给 Java 添加“函数类型”用于传递方法引用和 Lambda 表达式,但是这样的代价太高了,由于 Java 工程师都熟悉接口这一工具,因此使用接口来传递 Lambda 和方法引用。用于传递 Lambda 的接口就称为函数式接口。

@FunctionalInterface

函数式接口的标识是 @FunctionalInterface,它标注在接口上面,用于表示这是一个函数式接口。但实际上只要保证只有一个抽象方法,接口就是函数式接口,就可以代表一个 Lambda,就算没有添加这个注解也一样能工作。

所以这个注解的最大意义是用来告知程序员和告知编译器。当程序员看到这个注解就会意识到这是个函数式接口。当编译器识别到这个注解,就会验证接口内是否只有一个抽象方法,如果不是,会报告错误并拒绝编译:

image.png

或者

image.png

纯粹的函数式接口

函数式编程的思想是“无副作用”和“不变性”。如果一个方法既不修改输入参数的状态,也不修改其所属对象的状态,也不修改程序全局变量的状态,那么这个方法就是存粹的,或者无副作用的

存粹的函数是函数式编程的追求和指导理念,对于一个存粹的函数,任何对它的使用都是安全的,无论是同步还是并行状态,因为它不可能去改变任何其他对象的状态。

因此,如果一个函数式接口是存粹的函数式接口,那么我们在使用时,可以不考虑任何线程安全、变量逃逸的问题,可以以最安心的方式进行编程。

抛出异常也是对调用者状态的改变,因此一个会抛出异常的函数也不是存粹的函数。

但这只是指导思想,不是一切的准则,因为 Java 那“一切皆对象”的思想在大部分情况下是和“存粹的函数”相冲突的。我们的目的是善用这二者,让我们可以使用更完美的编程策略。而不是为了 A 而否定 B。

Java 中提供的函数式接口

Java 基本上为你能想到的 Lambda 签名的各种形式都提供了默认的函数式接口了,在此进行记录和列出,方便查阅。

Java 提供的函数式接口都在 java.util.function 包中。每个接口的抽象函数都会描述它的 Lambda 签名,但这种描述是非正式的,请注意。你想怎么描述都行,只要包含参数列表和返回值即可。

代码块 Runnable

Runnable 表示“可运行的”,该接口用于表示一个无参无返回值的函数

void run() 无输入,无输出,Lambda 签名为 () -> {...},单纯地执行函数中的代码。

public interface Runnable {
    public abstract void run();
}
复制代码

使用:

// Thread::Thread(Runnable target)
new Thread(() -> System.out.println("HELLO WORLD")).start();
复制代码

谓词 Predicate

一元谓词

Predicate 是“谓语”、“谓词”的意思。谓词表示用于判断,可以类比语法中的谓语,如 isis not不是。该接口用于表示一个对参数进行判断的函数

boolean test(T t) 输入 T 对象,输出布尔值,Lambda 签名为 t -> {...return boolean},若 t 满足条件就返回 true,否则返回 false。

public interface Predicate<T> {
    boolean test(T t);

    // 创建 Predicate 函数链,相当于与另一个 Predicate 进行与运算
    default Predicate<T> and(Predicate<? super T> other) {}
    
    // 创建相反逻辑的 Predicate
    default Predicate<T> negate() {}

    // 创建 Predicate 函数链,相当于与另一个 Predicate 进行或运算
    default Predicate<T> or(Predicate<? super T> other) {}
    
    /**
     * 创造一个 Predicate 函数,是一个全等函数,该函数用于判断输入参数是否等于 targetRef
     * 
     * @param targetRef 全等函数的判断目标
     * @param <T> 任意类型
     * @return 一个 Equal 比较函数
     */
    static <T> Predicate<T> isEqual(Object targetRef) {
        return (null == targetRef)
                ? Objects:
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值