JDK1.8源码解析——函数式接口@FunctionalInterface

本文简单介绍JDK1.8引入的新特性:函数式接口FunctionalInterface

定义

函数式接口:有且仅有一个抽象方法时(允许同时存在多个非抽象方法defaultstatic,JDK1.8引入),该抽象方法不涉及任何实际操作,只是为了满足某种功能而定义的一个抽象函数,即可视为函数式接口。如Callable, Runnable, Comparator等接口,在JDK8中都加入了@FunctionalInterface注解。

约束

使用函数式接口,需要满足以下条件:

  1. 有且只允许存在一个抽象方法(接口声明的方法默认是抽象的,如果一个接口中没有任何抽象方法,也就没有存在的意义,同时由于函数式接口主要服务于lambda匿名函数,如果接口声明中存在多个抽象方法,那么lambda表达式将无法判断待实现的匿名函数与哪个接口方法关联,因此需要保证抽象方法的唯一性);
  2. 允许定义static方法,通过定义类直接调用;
  3. 允许定义default方法,通过实现类调用,实现类可不用再实现default方法;
  4. 允许覆盖Object类中的,虽然覆盖后从语法上来讲也属于抽象方法;
  5. @FunctionalInterface非必须,即:接口没有添加该注解,也有可能是函数式接口,只要满足前4个条件,便是函数式接口,也就允许使用lambda表达式。
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
/**
* 一个合法的函数式接口
*/
@FunctionalInterface
public interface HelloService {
// 抽象方法(必须,有且仅有一个)
String hello(String name);
// 默认方法(可选,通过实现类调用HelloServiceImpl.defaultHello("xxx"))
default String defaultHello(String name) {
return "hello" + name + ", i'm default method";
}
// 静态方法(可选,通过定义类直接调用HelloService.staticHello("xxx"))
static String staticHello(String name) {
return "hello" + name + ", i'm static method";
}
// 覆盖Object类的equals方法(可选)
boolean equals(Object obj);
}

应用

上文中展示了一个函数式接口示例,使用lambda表达式,可以这样调用:

1
2
3
4
public static void main(String[] args) {
HelloService service = (String name) -> "hello " + name + ", i'm lambda.";
System.out.println(service.hello("DuckyRain"));
}

另外,JDK1.8中加入了java.util.function,提供了一些常见的函数式接口定义,如BiFunction

1
2
3
4
5
6
7
public static void main(String[] args) {
BiFunction<Integer, Double, String> biFunction = (Integer a, Double b) -> {
System.out.println("Compare a:" + a + " and b:" + b);
return a.doubleValue() == b ? "a = b" : "a != b";
};
System.out.println(biFunction.apply(2018, 2018.0));
}