JDK8: @FunctionalInterface介绍

159 阅读3分钟

最近看一些支持JDK1.8+的开源项目源码,发现代码中很多接口都添加了@FunctionalInterface注解,这个注解平时工作项目中用的不多,对这个注解也是一知半解的,所以决定去主动去查下该注解的知识,了解清楚它的设计意图及使用场景。

第一步,老规矩,直接看源码:


/**
 * An informative annotation type used to indicate that an interface
 * type declaration is intended to be a <i>functional interface</i> as
 * defined by the Java Language Specification.
 *
 * Conceptually, a functional interface has exactly one abstract
 * method.  Since {@linkplain java.lang.reflect.Method#isDefault()
 * default methods} have an implementation, they are not abstract.  If
 * an interface declares an abstract method overriding one of the
 * public methods of {@code java.lang.Object}, that also does
 * <em>not</em> count toward the interface's abstract method count
 * since any implementation of the interface will have an
 * implementation from {@code java.lang.Object} or elsewhere.
 *
 * <p>Note that instances of functional interfaces can be created with
 * lambda expressions, method references, or constructor references.
 *
 * <p>If a type is annotated with this annotation type, compilers are
 * required to generate an error message unless:
 *
 * <ul>
 * <li> The type is an interface type and not an annotation type, enum, or class.
 * <li> The annotated type satisfies the requirements of a functional interface.
 * </ul>
 *
 * <p>However, the compiler will treat any interface meeting the
 * definition of a functional interface as a functional interface
 * regardless of whether or not a {@code FunctionalInterface}
 * annotation is present on the interface declaration.
 *
 * @jls 4.3.2. The Class Object
 * @jls 9.8 Functional Interfaces
 * @jls 9.4.3 Interface Method Body
 * @since 1.8
 */
@Documented
@Retention(RetentionPolicy.RUNTIME)
@Target(ElementType.TYPE)
public @interface FunctionalInterface {}

注释里已清晰阐述了它的特征,其中的一些关键信息点:

  1. @since 1.8 说明是从JDK1.8才引入的

  2. functional interface 该注解是标记接口是functional interface。

所以想了解清楚该注解,关键就是要去了解functional interface了。

那什么是functional interface呢?

先说定义:函数式接口定义且只定义了一个抽象方法的接口。

注意:接口现在还可以拥有默认方法(即在类没有对方法进行实现时,其主体为方法提供默认实现的方法)。哪怕有很多默认方法,只要接口只定义了一个抽象方法,它就仍然是一个函数式接口。

所以,functional interface的定义,其实是简单且清晰的,它跟普通接口的唯一区别就是,它只定义了一个抽象方法

那它的作用是什么呢?

一句话描述就是:Lambda表达式允许你直接以内联的形式为函数式接口的抽象方法提供实现,并把整个表达式作为函数式接口的实例。直接说可能比较抽象,我们以一个例子来实战讲解下。

先定义一个接口:

public interface Hi {
    void hello();
}

然后有一个方法:

public void process(Hi hi) {
    hi.hello();
}

就这个简单的样例,我们看看怎么写代码实现方法的调用呢?

方法一:定义实现类,new对象

class HiImpl implements Hi {
    @Override
    public void hello() {
        System.out.println("hello world");
    }
}

Hi hiobj = new HiImpl();

process(hiobj);

方法二:匿名类

process(new Hi() {
    @Override
    public void hello() {
        System.out.println("hello world");
    }
});

方法三:Lambda

process(() -> System.out.println("hello world"));

方法三,就是functional interface作用的直接体现,它大大简化了我们代码的编写,很优雅。

结论

@FunctionalInterface的标注,用于表示该接口会被设计成一个函数式接口。@FunctionalInterface标注不是必须的,但是如果我们用@FunctionalInterface定义了一个接口,而实现时却不是一个函数式接口的话,编译器将会返回一个提示原因的错误。例如错误可能是 "Multiple non-overridingabstract methods found in interface Foo" , 表明存在多个抽象方法。

注意,虽然@FunctionalInterface不是必须的,但是对于我们实际为此意图而设计成函数接口的场景而言,显示加上它是比较好的做法,它可以清晰的表明该接口的用意,而避免误用。