Java lambda expression understanding

Keywords: Lambda Programming less Java

brief introduction

As a new feature of java8, lambda expression is oriented to function programming, which makes the code more concise and improves the programming efficiency. As a developer, we should not only learn to use it, but also understand the operation principle behind it

lambda general use

The rules used by lambda are roughly:
(parameter) - > {code body} (parameter) - > \ {code body \} (parameter) - > {code body}
The left bracket is not required. It can be omitted when there is only one parameter. The right bracket is not required. If there is only one line of code, it can be omitted
A small example of obtaining permission in MainActivity page:

private void getPermission(){
	RxPermissions permissions = new RxPermissions(this);
	permissions.request(Manifest.permission.CAMERA,
				Manifest.permission.INTERNET,)
	            .subscribe(aBoolean -> {
	               if(!aBoolean){
	                  Toast.makeText(this, "Unauthorized permission, some functions cannot be used", Toast.LENGTH_SHORT).show();
	               }
	        });
}

->The left parameter is a boolean, and the right side is the executing code body;
It's a lot less than the previous code. If it is implemented according to the previous code, it's like the following:

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

So how is this lambda expression implemented?
From the reverse perspective, I will use apk to reverse crack and view its smali code with apktool tool:
In the getPermission method:

.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
	#Partial omission
	# Here we have a new inner class - $$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
    # Subscription passed in v2, which is the internal class created above
    invoke-virtual {v1, v2}, Lio/reactivex/Observable;->subscribe(Lio/reactivex/functions/Consumer;)Lio/reactivex/disposables/Disposable;

    .line 125
    return-void
.end method

The above smali code roughly means that an internal class - $$Lambda$MainActivity$ccTQ_-iN8ZWh9xOrzs2GmyGpyIc has been created, and finally this internal class subscribes to the permission listening callback. Let's enter this internal class to have a look

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

# interfaces
//Implemented the Consumer interface
.implements Lio/reactivex/functions/Consumer;

# virtual methods
//Override accept method
.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;
	# The method lambda$getPermission lambda $getpermission $0  in MainActivity is removed
    invoke-static {v0, p1}, Lcom/iot/chinamobile/MainActivity;->lambda$getPermission$0(Lcom/iot/chinamobile/MainActivity;Ljava/lang/Boolean;)V

    return-void
.end method

The above code roughly means that the Comsumer interface is implemented in the current internal class, which is the reason why the permission subscriber can subscribe successfully, and finally call the lambda$getPermission lambda $getpermission $0 method of MainActivity; what is this method? Don't be afraid of trouble. The last step is to look at:

This is the java code:

if(!aBoolean){
 Toast.makeText(this, "Unauthorized permission, some functions cannot be used", Toast.LENGTH_SHORT).show();

Principle summary

The essence of the bottom layer of lambda is to create an internal class, and produce a static method in the class using the lambda expression. This static method is the code subject of lambda. The generated internal class is called in the overriding interface method, and this internal class is passed to the caller using the lambda. As shown in the following figure


The above is the internal implementation principle of lambda, and its implementation method is the same as the second way to go to new consumer by ourselves. In the coding process, it helps us reduce a lot of work, and the bottom layer helps us realize it automatically. In fact, it has one more step than going to new inner class by ourselves. When we go to new by ourselves, there will be no second step in the figure above, because the code in the method of the second step will be moved to the inner class Reduce one step of calling logic in the accept method of

In the end, how to choose or not? Different people have different opinions!

148 original articles published, 41 praised, 110000 visitors+
Private letter follow

Posted by ntohky14 on Tue, 11 Feb 2020 23:45:23 -0800