JAVA 函数式接口与lambda

1.函数式定义

什么是函数式接口呢?听起来很绕,我们可以这样理解:

可以接收lambda函数接口,就可以叫做函数式接口。

注意一个函数式接口里,只允许定义一个抽象方法。

在java里可以用@FunctionalInterface注解来标注函数式接口, 比如Runnable就是一个函数式接口:

@FunctionalInterface
public interface Runnable {
    void run();
}

2. 函数式接口有什么用?

现在我们知道了,函数式接口可以接收lambda表达式,首先我们分析下函数式接口有什么用。

2.1 函数式接口,可以接收一个方法!

Q: 那一个函数式接口,接收一个方法,又有何用?

答:可以让我们的代码更加灵活,其实方法作为参数,在很多脚本语言里是非常常见的,比如js、python。

我们思考一个问题:如何加强一个方法?

作为一名java开发,是不是一大堆名词涌入脑海?

比如AOP?代理模式?装饰者模式?

上述方法固然可以实现,但却很略显繁琐。

2.2 加强一个方法

假如我们要对下述方法做增强,

    public static void originMethod() {
        System.out.println("原方法");
    }

目标:在originMethod前后分别打印一些东西,

最简单的方法是不是这样:

    public static void decorate() {
        System.out.println("===方法前加强");
        originMethod();
        System.out.println("===方法后加强");
    }

但如果我们还需要加强其他的方法呢?再写一个decorate吗?

显然这种方法并不好,

那我们看看,使用函数式接口,怎么解决这个问题。

下面的代码是一个初版,先让大家回忆一下,Runnable是怎么用的。

    public static void originMethod() {
        System.out.println("原方法");
    }

    public static void main(String[] args) {

        Runnable runnable = new Runnable() {
            @Override
            public void run() {
                System.out.println("===方法前加强");
                originMethod();
                System.out.println("===方法后加强");
            }
        };
        runnable.run();
    }

但是上述代码不能通用,所以我们把加强方法抽取出来,变成方法decorateOriginMethod,代码如下:

可以看到,我们把originMethod()方法,传递给了形参method

你可能会说,哎不对,我传给形参method的是Runnable对象,你这么说也对,但我觉得不重要,因为上文提到:函数式接口里只有一个抽象方法。

所以形参method,接收的到底是函数式接口,还是方法,区别也不大。

2.3 lambda表达式简写函数式接口

刚才创建Runnble的代码很繁琐,使用lambda表达式简写如下:

    public static void main(String[] args) {
//        decorateOriginMethod(new Runnable() {
//            @Override
//            public void run() {
//                originMethod();
//            }
//        });
        // lambda表达式简写
        decorateOriginMethod(() -> originMethod());
    }

其实函数式接口就这么简单,至于那些什么Predicate,Supplier,Consumer这些花里胡哨的,与Runnable都是一样的原理,都是函数式接口而已,不要被吓到了。

区别在哪呢?其实就是:

函数式接口里,方法的入参和返回值类型不一样罢了

我们知道,Runnable入参和返回值都是void,

而java帮我们准备了一些默认的函数式接口,分别适用于不同的入参和返回值(如下图所示)。

当然你完全可以自己定义类似的函数式接口。

3.函数式接口,在框架里的使用

在阅读源码时,可以说函数式接口是绕不过去的。

尤其是Spring里特别多,而Mybatis里,倒是没怎么见到。

3.1 Spring事务里函数式接口的应用

我们看看如下方法的源码(删去了多于代码):org.springframework.transaction.support.TransactionTemplate#execute

    @Override
	@Nullable
	public <T> T execute(TransactionCallback<T> action) throws TransactionException {
            获取事务
			TransactionStatus status = this.transactionManager.getTransaction(this);
			T result;
			 
            //TransactionCallback是函数式接口,里面有唯一一个方法doInTransaction
            //执行真实的业务
			result = action.doInTransaction(status);
		
		    // 提交事务
			this.transactionManager.commit(status);
			return result;
		
	}

如上代码所示,我们把业务逻辑传给函数式接口TransactionCallback,然后框架帮我们增强了事务获取、提交、回滚等操作。

后记:

很久没发文章了,原力值没了,所以先写一篇。

其实函数式接口没什么神秘的,我个人感觉它就是一个新类型:方法。最典型的就是接收一个lambda表达式。

当然java类型里没有方法这一说,只是个人理解。

如果各位懂了,可以进一步趁热打铁,思考一下闭包是什么

其实java用函数式接口就可以实现闭包了!

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值