@FunctionalInterface函数式接口深入实践附demo 多种写法 提高代码可读性健壮性

@FunctionalInterface从1.8开始就可以使用了, 函数式接口,都有哪些规则呢,今天实践总结一下@FunctionalInterface的使用都有哪些方式和规则

特点

先说特点

  1. 唯一抽象方法:被@FunctionalInterface注解的接口必须保证只包含一个未实现的方法。如果接口中有多于一个抽象方法,编译器将会报错。
  2. Lambda表达式的载体:函数式接口是Java中Lambda表达式的目标类型。你可以通过Lambda表达式来创建该接口的实例,使得代码更加简洁和易于阅读。
  3. 默认方法和静态方法不受影响:虽然函数式接口只能有一个抽象方法,但是它可以包含任意数量的默认方法(default method)和静态方法。这些方法不会影响接口成为函数式接口的性质。
  4. 简化类型检查:编译器会在编译期检查带有@FunctionalInterface注解的接口,确保它满足函数式接口的条件。这样可以避免开发者无意中在接口中添加额外的抽象方法,导致Lambda表达式无法正常绑定。
  5. 面向函数式编程的支持@FunctionalInterface注解是Java 8为了支持函数式编程风格而引入的关键特性之一,它使得Java能够更好地融入函数式编程的世界,让开发者可以写出更加简洁、更具表达力的代码。

好了进入主题,开发离不开编码,实践是检验真理的唯一标准,demo来了
我先定义一个@FunctionalInterface注解的函数式接口

一般我把重点规则都注释到代码中了,大家注意看,看我良好的注释习惯哈哈

import com.mtgg.laoxiang.common.response.Result;

/**
 * 定义函数式接口
 */
@FunctionalInterface
public interface FunctionFruit {
    Result execute(String s);

    /**
     * 可定义变量,必须要有默认值
     */
    public static final String NAME = "变量name";

    /**
     * 可定义静态方法
     */
    static void drink() {
        System.out.println("可定义静态方法");
    }

    /**
     * 可定义默认方法
     */
    default void eat() {
        System.out.println("可定义默认方法");
    }
}

虽然用@FunctionalInterface注解,别忘了它本身是一个接口,可以被其他接口继承扩展

public interface IFunctionAnimal extends FunctionFruit {
    int apply();

    int dog();
}

然后可以有一个实现类,这个实现类会将FunctionFruit和IFunctionAnimal的接口都实现掉

/**
 * 有函数式的接口可以被实现使用
 */
@Component
public class IBirdImpl implements IFunctionAnimal {
    @Override
    public Result execute(String r) {
        System.out.println("bird 1");
        return Result.success("bird 1");
    }

    @Override
    public int apply() {
        System.out.println("bird 2");
        return 0;
    }

    @Override
    public int dog() {
        System.out.println("bird 3");
        return 0;
    }
}

然后我们定义一个Animal对象,这个对象我依赖了好几个函数式接口,包括官方的Function,我们自定义的FunctionFruit和IFunctionAnimal,说明我们的动作可以在执行前用对象传递,什么时候执行你说了算,什么时候执行我们往下看

import com.mtgg.laoxiang.common.response.Result;
import lombok.Getter;
import lombok.Setter;

import java.util.function.Function;

@Getter
@Setter
public class Animal{
    //现有函数是接口 作为属性 String作为入参,Result作为自定义返回封装类
    private Function<String, Result> function;
    //自定义函数式接口
    private FunctionFruit functionFruit;
    private FunctionFruit functionFruit2;
    private FunctionFruit functionFruit3;
    private FunctionFruit functionFruit4;
    private IFunctionAnimal IFunctionAnimal;

}

Result就是自己封装的一个通用返回类,有errorInfo,errorMsg,data

下面就是如何使用,先去看一遍代码,然后我再解释

import com.mtgg.laoxiang.common.response.Result;

import java.util.function.Function;

/**
 * 函数式接口实践
 * 一般函数式接口本身可以作为方法的参数(通过匿名内部类的方式实现);可以作为对象的属性;可以注入到全局map中;
 * 可以被集成然后注入使用;
 * {@link java.util.function.Supplier}
 * {@link java.util.function.Predicate}
 * {@link java.util.function.Consumer}
 * {@link java.util.function.Function}
 */
public class FTest {
    public static void main(String[] args) {
        FTest fTest = new FTest();
        Animal animal = fTest.buildAnimal();
        fTest.example(animal);
    }

    public Animal buildAnimal() {
        Animal animal = new Animal();
        animal.setIFunctionAnimal(new IBirdImpl());
        //封装的几个函数接口
        animal.setFunction(new Function<String, Result>() {
            @Override
            public Result apply(String s) {
                System.out.println("Function--->" + s);
                return Result.success();
            }
        });

        //TODO 写法1 匿名内部类
        animal.setFunctionFruit(new FunctionFruit() {
            @Override
            public Result execute(String r) {
                System.out.println("写法1 匿名内部类-->" + r);
                return Result.success();
            }
        });

        //TODO 写法2 方法引用 fruitTest必须为静态方法
        FunctionFruit functionFruit = FTest::fruitTest;
        animal.setFunctionFruit2(functionFruit);

        //TODO 写法3 实例方法引用 可不为静态方法
        FTest fTest = new FTest();
        FunctionFruit f3 = fTest::test2;
        animal.setFunctionFruit3(f3);

        //TODO 写法4
        FunctionFruit f4 = x -> Result.success();
        animal.setFunctionFruit4(f4);
        return animal;
    }


    public void example(Animal animal) {
        Result apply = animal.getFunction().apply("a");
        //可通过下级接口调用父级函数式接口
        Result cResult = animal.getIFunctionAnimal().execute("b");
        animal.getIFunctionAnimal().eat();
        animal.getIFunctionAnimal().apply();
        System.out.println(FunctionFruit.NAME);
        FunctionFruit.drink();
        animal.getFunctionFruit().execute("c");
        animal.getFunctionFruit2().execute("d");
        animal.getFunctionFruit3().execute("e");
        animal.getFunctionFruit4().execute("f");
    }

    public Result test2(String type) {
        System.out.println("写法3 实例方法引用-->" + type);
        return Result.success();
    }

    private static Result fruitTest(String type) {
        //可自定义逻辑……
        System.out.println("写法2 方法引用-->" + type);
        return Result.success();
    }

}

代码看完了,可以看出实际上我们执行是在example方法中,Animal对象作为上下文对象,我们写一个buildAnimal构建方法用来构建Animal对象,Animal定义那么多函数式接口是因为有不同的写法,都返回待执行的函数,可以让大家看到不同的写法的执行情况

函数式定义写法

写法一:匿名内部类

FunctionFruit f = new FunctionFruit() {
    @Override
    public Result execute(String r) {
        System.out.println("写法1 匿名内部类-->" + r);
        return Result.success();
    }
}

写法二:方法引用,大家可以看到有个限制,就是fruitTest必须为静态方法

FunctionFruit functionFruit = FTest::fruitTest;

    private static Result fruitTest(String type) {
        //可自定义逻辑……
        System.out.println("写法2 方法引用-->" + type);
        return Result.success();
    }

写法三:实例方法引用,可以看到这种方法解决了写法二必须为静态方法的问题

FTest fTest = new FTest();
FunctionFruit f3 = fTest::test2;

    public Result test2(String type) {
        System.out.println("写法3 实例方法引用-->" + type);
        return Result.success();
    }

写法四:简单函数直接定义,这种方式比较简单,所以直接定义可以用这种,比如a+b等等

FunctionFruit f4 = x -> Result.success();

example方法中是我们的调用,上面我们调用的各种地方的方法都有实践调用到,打印结果在这

Function—>a
bird 1
可定义默认方法
bird 2
变量name
可定义静态方法
写法1 匿名内部类–>c
写法2 方法引用–>d
写法3 实例方法引用–>e

在实际业务中大家可以斟酌使用,还是很有用的,逼格也挺高

大家可以实践一下,祝我们都能够写出漂亮的,健壮的,可扩展的,绝绝子的代码,see you later

  • 17
    点赞
  • 6
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 1
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

我是小酒

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值