记录:291
场景:为了理解和应用@FunctionalInterface注解。@FunctionalInterface是Java语言规范定义函数式接口的注解。它作用在只有一个抽象方法的接口。默认方法(default定义的方法)、静态方法、覆盖Object的方法(比如:boolean equals(Object obj))不计入抽象方法中。
版本:
JDK 1.8
Spring Boot 2.6.3
一、理解函数式接口
(1)@FunctionalInterface是Java语言规范定义函数式接口的注解。
(2)@FunctionalInterface作用在只有一个抽象方法的接口上。不能作用在annotation type, enum,class上。
(3)默认方法(default定义的方法)、静态方法、覆盖Object的方法(比如:boolean equals(Object obj))不算抽象方法。
(4)创建函数式接口实例方式,包括lambda表达式、方法引用、构造函数引用。
二、@FunctionalInterface的定义
@FunctionalInterface在jdk中位置:java.lang.FunctionalInterface。
jdk中的定义:
// Since:1.8
@Documented
@Retention(RetentionPolicy.RUNTIME)
@Target(ElementType.TYPE)
public @interface FunctionalInterface {}
三、应用@FunctionalInterface
在Java中的接口interface可以没有方法、只有一个方法、有多个方法等场景。
使用@FunctionalInterface注解到interface上,那么接口必须有且只能有一个抽象方法。如果没有一个抽象方法、或者有多个抽象方法情况下,编译器会提示报错。
1.函数式接口(抽象方法无入参)
1.1定义函数式接口Executable01
Executable01只有一个抽象方法且无入参。
@FunctionalInterface
public interface Executable01 {
void execute();
}
1.2应用函数式接口Executable01
在main函数中应用Executable01。
(1)使用匿名类方式调用接口。
(2)使用lambda表达式调用接口。
(3)实现Executable01接口,使用构造函数创建对象调用接口。
public class FunctionalPractice01 {
public static void main(String[] args) {
// 1. 使用匿名类方式调用接口
f1(new Executable01() {
@Override
public void execute() {
System.out.println("使用匿名类调用函数式接口.");
}
});
// 2. 使用lambda表达式调用接口
f1(() -> {
System.out.println("使用lambda表达式调用函数式接口.");
});
// 3. 实现Executable01接口,使用构造函数创建对象调用接口
f1(new Executable01Impl());
}
public static void f1(Executable01 exe01) {
System.out.println("f1开始...");
exe01.execute();
System.out.println("f1结束...");
}
public static class Executable01Impl implements Executable01 {
@Override
public void execute() {
System.out.println("实现Executable01接口,使用构造函数创建对象调用接口.");
}
}
}
2.函数式接口(抽象方法有入参)
2.1定义函数式接口Executable02
Executable02只有一个抽象方法且有入参。
@FunctionalInterface
public interface Executable02 {
void execute(String cityName);
}
2.2应用函数式接口Executable02
在main函数中应用Executable02。
(1)使用匿名类方式调用接口。
(2)使用lambda表达式调用接口。
(3)实现Executable02接口,使用构造函数创建对象调用接口。
public class FunctionalPractice02 {
public static void main(String[] args) {
// 1. 使用匿名类方式调用接口
f1(new Executable02() {
@Override
public void execute(String cityName) {
System.out.println("使用匿名类调用函数式接口.");
System.out.println("接收入参,城市名称: " + cityName);
}
}, "杭州");
// 2. 使用lambda表达式调用接口(cityName,代表抽象方法的入参)
f1((cityName) -> {
System.out.println("使用lambda表达式调用函数式接口.");
System.out.println("接收入参,城市名称: " + cityName);
}, "北京");
// 3. 实现Executable02接口,使用构造函数创建对象调用接口
f1(new FunctionalPractice02.Executable02Impl(), "厦门");
}
public static void f1(Executable02 exe02, String cityName) {
System.out.println("f1开始...");
exe02.execute(cityName);
System.out.println("f1结束...");
}
public static class Executable02Impl implements Executable02 {
@Override
public void execute(String cityName) {
System.out.println("实现Executable01接口,使用构造函数创建对象调用接口.");
System.out.println("接收入参,城市名称: " + cityName);
}
}
}
3.函数式接口包括多个方法
函数式接口包括多个方法,使用@FunctionalInterface后,抽象方法只能有一个。
3.1定义函数式接口Executable03
Executable03包含多个方法。
(1)抽象方法。
(2)默认方法。
(3)静态方法。
(4)equals是重写了Object的equals,不计入抽象方法。
@FunctionalInterface
public interface Executable03 {
// 1.抽象方法,且只有一个
void execute();
// 2.默认方法
default void execute01(){
System.out.println("函数式接口的默认(default)方法.");
}
// 3.静态方法
static void execute02(){
System.out.println("函数式接口的静态(static)方法.");
}
// 4. equals是重写了Object的equals,不计入抽象方法
boolean equals(Object obj);
}
3.2应用函数式接口Executable03
在main函数中应用Executable03。
(1)使用lambda表达式调用接口
public class FunctionalPractice03 {
public static void main(String[] args) {
f1(()->{
System.out.println("函数式接口的抽象(abstract)方法.");
});
}
public static void f1(Executable03 exe03) {
System.out.println("f1开始...");
// 1.抽象方法
exe03.execute();
// 2.默认方法
exe03.execute01();
// 3.静态方法
Executable03.execute02();
System.out.println("f1结束...");
}
}
四、小结
1.应用小结
使用@FunctionalInterface注解到Interface中,最大特点就是函数式接口的中这个抽象方法,使用者可以按需定义方法内的具体业务实现。将关注点只需聚焦到这一个抽象方法,其它事情交给Java底层去做。
2.jdk中函数式接口例子
在jdk 1.8中的java.util.function包中定义了很多函数式接口,这是研究@FunctionalInterface注解的很好素材。
以下,随机摘取了几个函数式接口,具体请移步jdk 1.8及其以上版本源码或者操作手册。
java.util.function.BiConsumer
java.util.function.Consumer
java.util.function.Function
java.util.function.DoubleFunction
java.util.function.IntFunction
java.util.function.Predicate
以上,感谢。
2022年8月18日