记录: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日