Java lambda表达式理解

简介

lambda表达式作为java8的新特性,面向函数式编程,使代码更加简洁,同时也提高编程效率;我们作为开发者,不仅要学会用,还要理解其背后的运作原理

lambda一般使用

lambda使用的规则大致为:
( 参 数 ) − > { 代 码 主 体 } (参数) -> \{ 代码主体 \} >{}
左边括号不是必须的,当只有一个参数时可以省略;右侧大括号也不是必须的,如果只有一行代码,可以省略
在MainActivity页面获取权限的小例子:

private void getPermission(){
	RxPermissions permissions = new RxPermissions(this);
	permissions.request(Manifest.permission.CAMERA,
				Manifest.permission.INTERNET,)
	            .subscribe(aBoolean -> {
	               if(!aBoolean){
	                  Toast.makeText(this, "未授权权限,部分功能不能使用", Toast.LENGTH_SHORT).show();
	               }
	        });
}

-> 左侧参数aBoolean,右侧是执行的代码主体;
确实比以前代码少了很多,如果按照以前的代码来实现的话,就像下面这样:

.subscribe(new Consumer<Boolean>() {
    @Override
    public void accept(Boolean aBoolean) throws Exception {
        Toast.makeText(MainActivity.this, "....", Toast.LENGTH_SHORT).show();
    }
});

那这个lambda表达式是如何实现的?
我从逆向的角度来看看,将apk使用apktool工具逆向破解查看其smali代码:
在getPermission方法内:

.method private getPermission()V
	.locals 4
	.line 116
	new-instance v0, Lcom/tbruyelle/rxpermissions2/RxPermissions;
	invoke-direct {v0, p0}, Lcom/tbruyelle/rxpermissions2/RxPermissions;-><init>(Landroid/support/v4/app/FragmentActivity;)V
	#部分省略...
	# 这里new了一个内部类-$$Lambda$MainActivity$ccTQ_-iN8ZWh9xOrzs2GmyGpyIc
	 new-instance v2, Lcom/iot/chinamobile/-$$Lambda$MainActivity$ccTQ_-iN8ZWh9xOrzs2GmyGpyIc;

    invoke-direct {v2, p0}, Lcom/iot/chinamobile/-$$Lambda$MainActivity$ccTQ_-iN8ZWh9xOrzs2GmyGpyIc;-><init>(Lcom/iot/chinamobile/MainActivity;)V

    .line 120
    # 订阅传入了v2,也就是上面创建的内部类
    invoke-virtual {v1, v2}, Lio/reactivex/Observable;->subscribe(Lio/reactivex/functions/Consumer;)Lio/reactivex/disposables/Disposable;

    .line 125
    return-void
.end method

上面smali代码大致意思是,创建了一个内部类-$$Lambda$MainActivity$ccTQ_-iN8ZWh9xOrzs2GmyGpyIc,并且最后这个内部类订阅了权限的监听回调;那我们进入这个内部类看看

.class public final synthetic Lcom/iot/chinamobile/-$$Lambda$MainActivity$ccTQ_-iN8ZWh9xOrzs2GmyGpyIc;
.super Ljava/lang/Object;
.source "lambda"

# interfaces
//实现了Consumer接口
.implements Lio/reactivex/functions/Consumer;

# virtual methods
//重写了accept方法
.method public final accept(Ljava/lang/Object;)V
    .locals 1

    iget-object v0, p0, Lcom/iot/chinamobile/-$$Lambda$MainActivity$ccTQ_-iN8ZWh9xOrzs2GmyGpyIc;->f$0:Lcom/iot/chinamobile/MainActivity;

    check-cast p1, Ljava/lang/Boolean;
	# 又去掉了MainActivity里面的方法lambda$getPermission$0
    invoke-static {v0, p1}, Lcom/iot/chinamobile/MainActivity;->lambda$getPermission$0(Lcom/iot/chinamobile/MainActivity;Ljava/lang/Boolean;)V

    return-void
.end method

上述代码大致意思是在当前内部类实现了Comsumer接口,这也是为什么权限订阅者可以订阅成功原因,最后又回去调用了MainActivity的lambda$getPermission$0方法;这个方法是什么呢?不要怕麻烦,最后一步了,在看看:
在这里插入图片描述
也就是java代码的这块:

if(!aBoolean){
 Toast.makeText(this, "未授权权限,部分功能不能使用", Toast.LENGTH_SHORT).show();

原理总结

lambda底层实质就是创建了一个内部类,同时在使用lambda表达式的类中生产一个静态方法,这个静态方法就是lambda的代码主题;由生产的内部类在重写接口方法中去调用;而这个内部类就传递给使用lambda的调用者;如下图
在这里插入图片描述

以上就是lambda的内部实现原理,其实现手段和第二种自己去new Comsumer一样的;在代码编写程面帮我们减少了很多工作,底层帮我们自动实现;其实比自己去new内部类还多了一个步骤,自己new时,在上图不会有第2步骤,因为会把第2个步骤的方法中代码移动到内部类的accept方法中去,减少一步调用逻辑

最终,如何取舍,仁者见仁,智者见智!

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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

打赏作者

帅气好男人_Jack

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

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

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

打赏作者

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

抵扣说明:

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

余额充值