函数式接口@FunctionalInterface
研究之前最好学习一下Lambda 表达式
参考
函数式接口概述
所谓的函数式接口,当然首先是一个接口,然后就是在这个接口里面只能有一个抽象方法。
这种类型的接口也称为SAM
接口,即Single Abstract Method interfaces
在 Java 中,Marker(标记)类型的接口是一种没有方法或属性声明的接口,简单地说,marker 接口是空接口。相似地,函数式接口是只包含一个抽象方法声明的接口。
java.lang.Runnable
就是一种函数式接口,在 Runnable 接口中只声明了一个方法 void run()
,相似地,ActionListener
接口也是一种函数式接口,我们使用匿名内部类来实例化函数式接口的对象,有了 Lambda 表达式,这一方式可以得到简化。
每个 Lambda 表达式都能隐式地赋值给函数式接口,例如,我们可以通过 Lambda 表达式创建 Runnable 接口的引用。
Runnable r = () -> System.out.println("hello world");
当不指明函数式接口时,编译器会自动解释这种转化:
new Thread(
() -> System.out.println("hello world")
).start();
因此,在上面的代码中,编译器会自动推断:根据线程类的构造函数签名 public Thread(Runnable r) { }
,将该 Lambda 表达式赋给 Runnable 接口。
以下是一些 Lambda 表达式及其函数式接口:
Consumer<Integer> c = (int x) -> { System.out.println(x) };
BiConsumer<Integer, String> b = (Integer x, String y) -> System.out.println(x + " : " + y);
Predicate<String> p = (String s) -> { s == null };
@FunctionalInterface
是 Java 8 新加入的一种接口,用于指明该接口类型声明是根据 Java 语言规范定义的函数式接口。Java 8 还声明了一些 Lambda 表达式可以使用的函数式接口,当你注释的接口不是有效的函数式接口时,可以使用 @FunctionalInterface
解决编译层面的错误。
特点
- 接口有且仅有一个抽象方法(
abstract
) - 允许定义静态方法
static
- 允许定义默认方法
default
- 允许java.lang.Object中的
public
方法 - 该注解不是必须的,如果一个接口符合"函数式接口"定义,那么加不加该注解都没有影响。加上该注解能够更好地让编译器进行检查。如果编写的不是函数式接口,但是加上了
@FunctionInterface
,那么编译器会报错
符合函数式接口的,可以不加这个注解,不是函数式接口的加了注解会报错(建议加上,否则被别人改了还不报错就坏了)
定义
比如可以这样定义
@FunctionalInterface
public interface WorkerInterface {
//抽象关键字可以省略
public void doSomeWork();
//public void doSomeMoreWork();//根据定义,函数式接口只能有一个抽象方法,如果你尝试添加第二个抽象方法,将抛出编译时错误。
}
//若是加上第二个抽象方法会报错
Unexpected @FunctionalInterface annotation
@FunctionalInterface ^ WorkerInterface is not a functional interface multiple
non-overriding abstract methods found in interface WorkerInterface 1 error
也可以
// 正确的函数式接口
@FunctionalInterface
public interface TestInterface {
// 抽象方法
public void sub();
// java.lang.Object中的public方法,可以留着
public boolean equals(Object var1);
// 默认方法 default可以
public default void defaultMethod(){
}
// 静态方法 static方法可以
public static void staticMethod(){
}
}
// 错误的函数式接口(有多个抽象方法)
@FunctionalInterface
public interface TestInterface2 {
void add();
void sub();
}
使用
- 案例1
//定义一个函数式接口
@FunctionalInterface
public interface WorkerInterface {
public void doSomeWork();
}
public class WorkerInterfaceTest {
public static void execute(WorkerInterface worker) {
//传入实现的函数式接口类,调用接口方法
worker.doSomeWork();
}
public static void main(String[] args) {
//普通调用方法
execute(new WorkerInterface() {
//调用WorkerInterface,实现接口
@Override
public void doSomeWork() {
System.out.println("Worker invoked using Anonymous class");
}
});
//Lambda 优化
execute(() -> System.out.println("Worker invoked using Lambda expression"));
}
}
/////////
输出:
Worker invoked using Anonymous class
Worker invoked using Lambda expression