被@FunctionalInterface注解标记的类型表明这是一个函数接口。从概念上讲,函数接口只有一个抽象方法。如果接口声明的抽象方法覆写Object类的公共方法,那这方法不算作接口的抽象方法,因为接口具有Object方法的默认实现。
先看Java SE 8中@FunctionalInterface注解是如何声明的:
@Documented
@Retention(RetentionPolicy.RUNTIME)
@Target(ElementType.TYPE) public @interface FunctionalInterface {}
由Java源代码声明我们了解到:@FunctionalInterface注解,只能用于类。其实,它的应用范围更小,只能应用于接口类型。
我们可以使用lambda表达式,方法引用或构造函数引用创建功能接口的实例。
如果一个类型被此标记的话,如果不是以下情况,编译器会报错:
- 此类型是接口类型并且不是注解类型、枚举或类
- 标记的类型满足函数接口的要求
但是,无论接口声明中是否标记了@FunctionalInterface注解,编译器都会将满足函数接口定义的任何接口视为函数接口。
首先,我们先看看函数接口在《Java语言规范》中是怎么定义的:
函数接口是一种只有一个抽象方法(除Object中的方法之外)的接口,因此代表一种单一函数契约。函数接口的抽象方法可以是从超级接口继承而来,但继承而来的方法应该是覆写等效的( override-equivalent ),这种情况,在逻辑上,代表一个方法。
创建函数接口实例,除了以声明和实例化类的形式这种常规过程之外,还可以使用方法引用表达式和lambda表达式创建函数接口的实例。
声明函数接口时,除了要声明一个抽象方法,还可以声明覆写Object类中的public方法以及default方法。
以下举例说明:
示例一:最常见的函数接口形式
package org.springmorning.demo.javabase.annotation.pre;
/**
* @author 春晨
* @date 2019/1/20 19:59
* Copyright ©2019 春晨 https://www.cnblogs.com/springmorning/p/10296022.html
*
* @Description 最常见的函数接口形式:只声明了一个抽象方法
*/
public interface Job {
void execute();
}
示例二:最常见的泛型函数接口形式
package org.springmorning.demo.javabase.annotation.pre;
/**
* @author 春晨
* @date 2019/1/20 21:13
* Copyright ©2019 春晨 https://www.cnblogs.com/springmorning/p/10296022.html
*
* @Description 最常见的泛型函数接口形式:只声明了一个抽象方法
*/
public interface Work {
T doWork(Object o);
}
示例三:只包含覆写Object的公共方法的接口,不属于函数接口
package org.springmorning.demo.javabase.annotation.pre;
/**
* @author 春晨
* @date 2019/1/20 20:16
* Copyright ©2019 春晨 https://www.cnblogs.com/springmorning/p/10296022.html
*
* @Description 覆写Object的equals方法,不属于函数接口
*/
public interface NonFunctionInterface {
boolean equals(Object obj);
}
示例四:继承父接口的Object类的公共方法,自身声明了一个非Object类的公共方法,也属于函数接口
package org.springmorning.demo.javabase.annotation.pre;
/**
* @author 春晨
* @date 2019/1/20 20:22
* Copyright ©2019 春晨 https://www.cnblogs.com/springmorning/p/10296022.html
*
* @Description 继承的父接口,虽然不是函数接口,但是此接口声明了抽象方法,此方法不属于Object类的public方法,因此属于函数接口
*/
public interface EquivalentInterface extends NonFunctionInterface{
int compare(T o1, T o2);
}
示例五:包含覆写Object类公共方法的函数接口
/**
* @author 春晨
* @date 2019/1/20 20:24
* Copyright ©2019 春晨 https://www.cnblogs.com/springmorning/p/10296022.html
*
* @Description 包含覆写Object中equals方法的函数接口
*/
public interface EquivalentInterface {
int compare(T o1, T o2);
boolean equals(Object obj);
}
示例六:既包含覆写Object中equals方法,又包含default方法的函数接口
/**
* @author 春晨
* @date 2019/1/20 20:26
* Copyright ©2019 春晨 https://www.cnblogs.com/springmorning/p/10296022.html
*
* @Description 既包含覆写Object中equals方法,又包含default方法的函数接口
*/
public interface EquivalentInterface {
int compare(T o1, T o2);
boolean equals(Object obj);
default String name(){
return "EquivalentInterface";
}
}
示例七:从父接口继承覆写等效方法的函数接口
package org.springmorning.demo.javabase.annotation.pre;
/**
* @author 春晨
* @date 2019/1/20 20:36
* Copyright ©2019 春晨 https://www.cnblogs.com/springmorning/p/10296022.html
*
* @Description 函数接口的抽象方法可以是从X、Y两个父接口继承而来,但继承而来的valueOf方法是覆写等效,因此Z接口也属于函数接口
*/
interface X{
int valueOf(String x);
}
interface Y{
int valueOf(String y);
}
public interface Z extends X, Y{
}
示例八:从父接口继承覆写等效方法的函数接口
package org.springmorning.demo.javabase.annotation.pre;
/**
* @author 春晨
* @date 2019/1/20 20:41
* Copyright ©2019 春晨 https://www.cnblogs.com/springmorning/p/10296022.html
*
* @Description 函数接口的抽象方法可以是从A、B两个父接口继承而来,但继承而来的convert方法是覆写等效,因此C接口也属于函数接口
*/
interface A{
Iterable convert(Iterable arg);
}
interface B{
Iterable convert(Iterable arg);
}
public interface C extends A, B{
}
示例九:从父接口继承覆写等效方法的泛型函数接口
package org.springmorning.demo.javabase.annotation.pre;
/**
* @author 春晨
* @date 2019/1/20 20:53
* Copyright ©2019 春晨 https://www.cnblogs.com/springmorning/p/10296022.html
*
* @Description 函数接口的抽象方法可以是从O、P两个父接口继承而来,但继承而来的classInfo方法是覆写等效,因此Q接口也属于函数接口
*/
interface O {
T classInfo(Class> c);
}
interface P {
S classInfo(Class> c);
}
public interface Q extends O, P{
}
最主要的作用就是lambda表达式