JDK 8 函数型接口
一、简介
如果一个接口中只有一个方法,那么该接口就称为函数型接口,对于函数型接口,我们会加上注解 @FunctionalInterface 进行校验,如果某一个接口中存在两个抽象方法,那么它就会报错.
例如 JDK 8 内置的四大函数型接口之一 Function
@FunctionalInterface
public interface Function<T, R> {
R apply(T t);
default <V> Function<V, R> compose(Function<? super V, ? extends T> before) {
Objects.requireNonNull(before);
return (V v) -> apply(before.apply(v));
}
default <V> Function<T, V> andThen(Function<? super R, ? extends V> after) {
Objects.requireNonNull(after);
return (T t) -> after.apply(apply(t));
}
static <T> Function<T, T> identity() {
return t -> t;
}
}
二、函数型接口中的 default、static 修饰的方法
函数型接口的定义不是只能有一个抽象方法吗,为什么 JDK 8 内置的函数型接口 Function 有 apply、compose、andThen、identity 四个方法呢,这不是和定义相违背了吗?
JDK 8 之前接口的结构如下
interface 接口名{
静态常量;
抽象方法;
}
JDK 8 及之后接口的结构如下
interface 接口名{
静态常量;
抽象方法;
默认方法;
静态方法;
}
那么默认方法、静态方法有什么用呢,下面我们就来探究一下
2.1、默认方法
假设有这么一个场景,我们需要在 Map 接口中增加一个抽象方法,扩展 Map 集合的功能
一般的做法是在顶层接口中增加新的抽象方法,然后实现接口的子类重写该新增的方法即可,但是 Map 集合的实现类众多,每个实现类都去重写这个新增的方法,那么这个工作量是比较大的

如何解决这个问题呢,这就需要使用 JDK 8 接口新特性默认方法
接口中的默认方法使用 default 关键字修饰
// 自定义接口
interface A {
void flying(String userName);
// 注意接口中的默认方法和接口中的抽象方法不同,接口中的默认方法是有方法体的
default void swimming(){
System.out.println("接口 A 中的 swimming 方法");
}
}
class B implements A{
@Override
public void flying(String userName) {
System.out.println("实现类 B 中的 flying 方法");
}
}
public class LambdaDemo {
public static void main(String[] args) {
A a = new B();
a.swimming();
}
}
输出结果

可以看出,实现类 B 并没有重写接口 A 中的 swimming 方法,但是却可以调用 swimming 方法,说明接口中的默认方法是可以被继承的
既然可以被继承,那么可以被重写吗?
// 自定义接口
interface A {
void flying(String userName);
// 注意接口中的默认方法和接口中的抽象方法不同,接口中的默认方法是有方法体的
default void swimming(){
System.out.println("接口 A 中的 swimming 方法");
}
}
class B implements A{
@Override
public void flying(String userName) {
System.out.println("实现类 B 中的 flying 方法");
}
@Override
public void swimming() {
System.out.println("实现类 B 中的 swimming 方法");
}
}
public class LambdaDemo {
public static void main(String[] args) {
A a = new B();
a.swimming();
}
}
输出结果

接口中的默认方法也是可以被重写的
2.2、静态方法
// 自定义接口
interface A {
void flying(String userName);
// 注意接口中的默认方法和接口中的抽象方法不同,接口中的默认方法是有方法体的
static void jumping(){
System.out.println("接口 A 中的 swimming 方法");
}
}
class B implements A{
@Override
public void flying(String userName) {
System.out.println("实现类 B 中的 flying 方法");
}
}
public class LambdaDemo {
public static void main(String[] args) {
// 接口中的静态方法不能被继承,由于是静态方法也不存在重写一说,只能通过 类名.方法名() 的方式进行调用
A.jumping();
}
}
输出结果

2.3、总结
上面我们想往 Map 接口中增加一个新方法,但是又不想去每个实现类里面重写该方法,这种场景下就可以将该方法定义为默认(default)方法,即子类中
1、接口中的默认方法(default)、静态方法(static)与接口中的抽象方法不同,它们是有方法体的
2、接口中的默认方法可以被子类继承、重写
3、接口中的静态方法只能使用类名进行调用

浙公网安备 33010602011771号