android lambdaの使用概要と運行原理

7790 ワード

関数式プログラミングをサポートするため、Java 8はLambda式を導入し、Android NはJava 8をサポートし始めた.Java 8の新しい特性は、開発者たちの大きな福音であり、happyのコードでLambdaを使用したり、Streamを呼び出したりすることができます.この文章は主にLambdaの特性を紹介し、原現を実現し、使用方法、Java 8の新しい特性と使い方について、もう一つの博文をまとめます.Lambdaを使用すると、コードの作成を大幅に減らすことができ、最も重要な部分だけに注目することができます.コードの読みやすさは悪くなりますが、慣れるとLambda式が好きになり、コードがきれいになったのはほんの少しではありません.
みんながlambda式を使った以上、どうして私がこの文章を書くのか、私たちの開発者はもちろん主義ばかり持って来てはいけません.知っていても知っています.Java 8ではLambda式をどのように実現しているのでしょうか.Lambda式をコンパイルすると、いったい何が生成されるのでしょうか.匿名の内部クラスと何が違いますか?その仕組みを身につけておけば、後で面接で聞かれても、1、2、3回は言えない.
1.lambda式は内部クラスを使用して実現されますか?
Lambda式は単純な匿名内部クラスではありません.匿名内部クラスを使用すると、コンパイラは匿名内部クラスごとにクラスファイルを作成します.クラスは使用前にクラスファイルをロードして検証する必要があります.このプロセスはアプリケーションの起動性能に影響します.クラスファイルのロードは、lambdaが匿名の内部クラスで実装されると、アプリケーションのメモリ占有量が増加し、lambda式が匿名の内部クラスのバイトコード生成メカニズムにバインドされるため、時間がかかる操作である可能性があります.したがってlambda式は匿名の内部クラスを用いて実現されるわけではない.次のコードを分析します.
public class Lambda {
    Function f = s -> Integer.parseInt(s);
}

上記のクラスがコンパイルされた後に生成されたバイトコードを表示します.
0: aload_0
1: invokespecial #1 // Method java/lang/Object."":()V
4: aload_0
5: invokedynamic #2, 0 // InvokeDynamic
                  #0:apply:()Ljava/util/function/Function;
10: putfield #3 // Field f:Ljava/util/function/Function;
13: return

lambdaはjavaの動的命令を使用していることがわかりますので、lambda内部では内部クラスを使用して実現されていません.
2.lambda式はどのように実行されますか.
Lambda式は翻訳ポリシーを実行に延期し、主に式をバイトコードinvoked dynamic命令に変換し、上でコンパイルしたバイトコードのように、主に以下の2つのステップがある:1)invoked dynamic呼び出しポイント(dynamicファクトリ)を生成し、lambda式が呼び出されると、lambda式が変換された関数インタフェースのインスタンスを返す.2)lambda式のメソッドボディをinvoked dynamic命令呼び出しのためのメソッドに変換する.ほとんどの場合、lambda式は匿名の内部クラスよりもパフォーマンスが優れています.
3.lambda式はどのように機械認識のコードに翻訳しますか?
Lambda式を実際の実行コードに翻訳するには、変数の取得と非変数の取得方法、すなわち外部変数にアクセスする必要があるかどうかに分けられます.次の式について説明します.
public class Lambda {
    Function f = s -> Integer.parseInt(s);
}

1)変数取得を行わないlambda式の場合、その方法実装は、同じ署名を有する静的方法に抽出され、この静的方法はlambda式と同じクラスにある.上の式は次のようになります.
static Integer lambda$1(String s) {
    return Integer.parseInt(s);
}

2)変数をキャプチャするlambda式の場合、lambda式は依然として静的方法に抽出され、キャプチャされた変数は通常のパラメータと同じようにこの方法に伝達される.
static Integer lambda$1(int offset, String s) {
    return Integer.parseInt(s) + offset;
}

4.lambda式は匿名内部に対してどのような利点がありますか.
1)接続面では,前述したlambdaファクトリに相当し,このステップは匿名内部クラスのクラスロードプロセスに相当し,プリヒートには時間がかかるが,呼び出しポイント接続の増加に伴いコードが頻繁に呼び出されると性能が向上する一方,接続が頻繁でなければlambdaファクトリメソッドも匿名内部クラスロードよりも速く,最高100倍に達する.2)lambdaが変数をキャプチャしない場合、自動的に最適化され、lambdaファクトリに基づいて追加のオブジェクトの作成を回避します.匿名の内部クラスは、外部クラスのインスタンスの作成に対応し、より多くのメモリが必要です.
5.lambda式はjava特有ですか?
Lambda式はjava 8特有ではなく、scalaは匿名の内部クラスでlambda式をサポートしたことがある.
6.android studioでlambdaを使用する
1)プロジェクトのbuild.gradleのbuildscriptのdependenciesの下で依存を加える:
classpath 'me.tatarka:gradle-retrolambda:3.3.1'

2)appのbuild.gradleにlambdaパッケージを最上位に導入する
apply plugin: 'me.tatarka.retrolambda'

android閉パッケージラベルの下に追加します.
compileOptions {
        sourceCompatibility 1.8
        targetCompatibility 1.8
    }

これによりプログラム内でlambdaを直接使用して迅速に開発することができる.
7.lambdaの一般的な書き換え
1)setOnItemClickListenerの書き換え
 //  
xxxListView.setOnItemClickListener(new AdapterView.OnItemClickListener() {
            @Override
            public void onItemClick(AdapterView> parent, View view, int position, long id) {
                //Do something
            }
});
//  lambda 
xxxListView.setOnItemClickListener((parent,view,position,id)->{
    //Do something
});
//  
xxxListView.setOnItemClickListener((a,b,c,d)->{
    //Do something
});

2)onClickListenerの書き方
//  
View.OnClickListener onClickListener = new View.OnClickListener(){ 
        @Override 
        public void onClick(View view) {
                   handleClick(); 
        }
});
findViewById(R.id.someView).setOnClickListener(onClickListener);
//  lambda 
View.OnClickListener onClickListener = view -> handleClick();
findViewById(R.id.someView).setOnClickListener(onClickListener);

3)RxjavaのActionまたはFun関数に遭遇した場合:以下の要求ユーザ情報のようにsubscribe(Consumer)
//                 Api.getInstance().getRoleInfo(requestEnvelope)
                .subscribeOn(Schedulers.io())
                .observeOn(AndroidSchedulers.mainThread())
                .subscribe(new Consumer() {
                    @Override
                    public void accept(ResponseEnvelope responseEnvelope) throws Exception {
                        //response(responseEnvelope);
                    }
                }, new Consumer() {
                    @Override
                    public void accept(Throwable throwable) throws Exception {
                        //throwException(throwable);
                    }
                });
//  lambda                 Api.getInstance().getRoleInfo(requestEnvelope)
                .subscribeOn(Schedulers.io())
                .observeOn(AndroidSchedulers.mainThread())
                .subscribe(this::response, this::throwException));

クラスに対応するresponseメソッドとthrowExceptionメソッドを定義するだけで、より簡潔で直感的に使用できます.