Java 函数式接口

Java 函数式接口,用户希望使用现有的函数式接口,或编写自定义函数式接口,创建只包含单一抽象方法的接口,并为其添加 @FunctionalInterface 注解。Java 8 引入的函数式接口是一种包含单一抽象方法的接口,因此可以作为 lambda 表达式或方法引用的目标。

Java 函数式接口 问题描述

用户希望使用现有的函数式接口,或编写自定义函数式接口。

Java 函数式接口 解决方案

创建只包含单一抽象方法的接口,并为其添加 @FunctionalInterface 注解。

Java 函数式接口 具体实例

Java 8 引入的函数式接口是一种包含单一抽象方法的接口,因此可以作为 lambda 表达式或方法引用的目标。
关键字 abstract 在这里很重要。在 Java 8 之前,接口中的所有方法被默认视为抽象方法,不需要为它们添加 abstract
我们定义一个名为 PalindromeChecker(回文检查器)的接口,如例 1-22 所示。

例 1-22 回文检查器接口

@FunctionalInterface
public interface PalindromeChecker {
    boolean isPalidrome(String s);
}
Java

由于接口中的所有方法均为 public 方法4,可以省略访问修饰符,如同省略 abstract 关键字一样。
4至少在 Java 9 之前,接口中也允许使用 private 方法。更多详细信息,参见范例 接口中的私有方法

由于 PalindromeChecker 仅包含一个抽象方法,它属于函数式接口。Java 8 在 java.lang 包中提供了 @FunctionalInterface 注解,可以应用到函数式接口,如例 1-22 所示。
@FunctionalInterface 注解并非必需,但使用它是一种好习惯,原因有两点。首先,@FunctionalInterface 注解会触发编译时校验(compile-time check),有助于确保接口符合要求。如果接口不包含或包含多个抽象方法,程序将提示编译错误。
其次,添加 @FunctionalInterface 注解后,会在 Javadoc 中生成以下语句:

Functional Interface:
This is a functional interface and can therefore be used as the assignment
target for a lambda expression or method reference.
Java

函数式接口中同样可以使用 defaultstatic 方法。由于这两种方法都有相应的实现,它们与“仅包含一个抽象方法”的要求并不矛盾。示例代码如例 1-23 所示。

例 1-23 MyInterface 是一个包含静态方法和默认方法的函数式接口

@FunctionalInterface
public interface MyInterface {
    int myMethod();// int myOtherMethod();  ➋

    default String sayHello() {
        return "Hello, World!";
    }

    static void myStaticMethod() {
        System.out.println("I'm a static method in an interface");
    }
}
Java

❶ 单一抽象方法
❷ 如果这条语句未被注释掉,MyInterface 将不再是函数式接口
可以看到,如果 myOtherMethod 方法未被注释掉,MyInterface 就不再满足函数式接口的要求,@FunctionalInterface 注解将报错:“存在多个非重写的抽象方法。”
接口可以继承其他接口(甚至不止一个)。@FunctionalInterface 注解将对当前接口进行校验。因此,如果一个接口继承现有的函数式接口后,又添加了其他抽象方法,该接口就不再是函数式接口,如例 1-24 所示。

例 1-24 继承函数式接口的 MyChildInterface 不再属于函数式接口

public interface MyChildInterface extends MyInterface {
    int anotherMethod();}
Java

➊ 其他抽象方法
MyChildInterface 不属于函数式接口,因为它包含两个抽象方法:继承自 MyInterfacemyMethod 和声明的 anotherMethod。即便没有添加 @FunctionalInterface 注解,代码也可以编译,因为 MyChildInterface 就是一个标准接口,但无法作为 lambda 表达式的目标。
此外,还有一种不太常见的情况值得注意。Comparator 接口用于排序,其他范例将对此进行讨论。查看 Comparator 接口的 Javadoc 信息,并点击 Abstract Methods(抽象方法)标签后,将显示以下信息(图 1-1)。

图 1-1:Comparator 接口包含的抽象方法
可以看到,Comparator 接口包含两种抽象方法,且其中一种方法是在 java.lang.Object 类中实际实现的,那么 Comparator 为什么还属于函数式接口呢?
这里的特别之处在于,图中显示的 equals 方法来自 Object 类,因此已有一个默认的实现。根据 Javadoc 的描述,出于性能方面的考虑,用户可以提供满足相同契约(interface contract)的自定义 equals 方法,但不对该方法进行重写“始终是安全的”。
根据函数式接口的定义,Object 类中的方法与单一抽象方法的要求并不矛盾,因此 Comparator 仍然属于函数式接口。

Python教程

Java教程

Web教程

数据库教程

图形图像教程

大数据教程

开发工具教程

计算机教程

登录

注册