最近看一些支持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 {}
注释里已清晰阐述了它的特征,其中的一些关键信息点:
-
@since 1.8 说明是从JDK1.8才引入的
-
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不是必须的,但是对于我们实际为此意图而设计成函数接口的场景而言,显示加上它是比较好的做法,它可以清晰的表明该接口的用意,而避免误用。