ラムダ式の原則と例

ラムダ式の原則と例

ラムダ式

ラムダ式 (クロージャとも呼ばれる) は、Java 8 のリリースを推進した最も重要な新機能です。
Lambda では、関数をメソッド パラメーターとして使用できます (関数はパラメーターとしてメソッドに渡されます)。
ラムダ式を使用すると、コードをより簡潔かつコンパクトにすることができます。

1. 需要分析

新しいスレッドを作成し、スレッドで実行するタスクを指定します

    パブリック静的voidメイン(String[] args) {
        // 新しいスレッドを開始します new Thread(new Runnable() {
            @オーバーライド
            パブリックボイド実行() {
                System.out.println("新しいスレッドで実行されたコード: "+Thread.currentThread().getName());
            }
        })。始める();
        System.out.println("メインスレッドのコード: " + Thread.currentThread().getName());
    }

コード分​​析:

  1. Thread クラスには、パラメータとして Runnable インターフェースが必要です。このインターフェースでは、抽象メソッド run がスレッド タスクの内容を指定するために使用されるコア メソッドです。
  2. 実行メソッド本体を指定するには、Runnable実装クラスを使用する必要があります。
  3. Runnable実装クラスの定義を保存するには、匿名内部クラスを使用する必要があります。
  4. 抽象 run メソッドをオーバーライドして書き直す必要があります。すべてのメソッド名、メソッド パラメーター、メソッドの戻り値は、エラーなしで書き直す必要があります。
  5. 実際、私たちが気にするのはメソッド本体のコードだけです

2. 初心者のためのラムダ式

ラムダ式は匿名関数であり、渡すことができるコードとして理解できます。

new Thread(() -> { System.out.println("新しいスレッド ラムダ式..." +Thread.currentThread().getName()); })
。始める();
ラムダ式の利点: 匿名内部クラスの使用が簡素化され、構文もシンプルになります。

匿名内部クラスの構文は冗長です。ラムダ式を体験した後、ラムダ式は匿名内部クラスを簡素化する方法であることがわかりました。

3. ラムダ構文ルール

Lambda はオブジェクト指向のルールと規制を排除します。Lambda の標準形式は 3 つの部分で構成されます。

(パラメータ型パラメータ名) -> {
コード本体;
}

フォーマットの説明:

  • (パラメータタイプ パラメータ名): パラメータリスト
  • {コード本体;} : メソッド本体
  • -> : 矢印、パラメータリストとメソッド本体を分離する

3.1 ラムダ演習1

パラメータと戻り値のないLambdaを練習する

インターフェースの定義

パブリックインターフェースUserService{
    void 表示();
}

次に、メインメソッドを作成します。

パブリッククラスDemo03Lambda {

    パブリック静的voidメイン(String[] args) {
        goShow(新しいUserService() {
            @オーバーライド
            パブリックボイドショー(){
                System.out.println("実行されたメソッドを表示...");
            }
        });
        System.out.println("-----------");
        goShow(() -> { System.out.println("Lambda show メソッドが実行されました..."); });
    }

    パブリック静的void goShow(UserService userService){
        ユーザーサービスを表示します。
    }
}

出力:

show メソッドは次のように実行されます...
----------
Lambda の show メソッドが実行されます...

3.2 ラムダ演習2

パラメータと戻り値を使用してラムダ式のケースを完了する

Personオブジェクトの作成

@データ
@AllArgsコンストラクタ
@NoArgsコンストラクタ
パブリッククラスPerson {

    プライベート文字列名;

    プライベート整数の年齢。

    プライベート整数の高さ;

}

次に、複数の Person オブジェクトを List コレクションに保存し、これらのオブジェクトを年齢順に並べ替えます。

    パブリック静的voidメイン(String[] args) {
        リスト<Person> リスト = 新しい ArrayList<>();
        list.add(new Person("ジェイ・チョウ",33,175));
        list.add(new Person("アンディ・ラウ",43,185));
        list.add(new Person("周星驰",38,177));
        list.add(new Person("郭富城",23,170));

        Collections.sort(リスト、新しいComparator<Person>() {
            @オーバーライド
            パブリック int 比較(Person o1、Person o2) {
                o1.getAge()-o2.getAge() を返します。
            }
        });
        for (人 人 : リスト) {
            System.out.println(人);
        }
    }

sortメソッドの2番目のパラメータはComparatorインターフェースの匿名内部クラスであり、実行されるメソッドにはパラメータと戻り値があるため、Lambda式として書き直すことができることがわかった。

    パブリック静的voidメイン(String[] args) {
        リスト<Person> リスト = 新しい ArrayList<>();
        list.add(new Person("ジェイ・チョウ",33,175));
        list.add(new Person("アンディ・ラウ",43,185));
        list.add(new Person("周星驰",38,177));
        list.add(new Person("郭富城",23,170));

        /*Collections.sort(リスト、新しいComparator<Person>() {
            @オーバーライド
            パブリック int 比較(Person o1、Person o2) {
                o1.getAge()-o2.getAge() を返します。
            }
        });
        for (人 人 : リスト) {
            System.out.println(人);
        }*/
        System.out.println("------");
        Collections.sort(リスト、(Person o1、Person o2) -> {
            o1.getAge() - o2.getAge() を返します。
        });
        for (人 人 : リスト) {
            System.out.println(人);
        }
    }

出力

人物(名前=アーロン・クォック、年齢=23、身長=170)
人物(名前=ジェイ・チョウ、年齢=33、身長=175)
人物(名前=周星驰、年齢=38、身長=177)
人物(名前=アンディ・ラウ、年齢=43、身長=185)

4. @FunctionalInterface アノテーション

@FunctionalInterface は JDK8 で追加された新しい機能アノテーションであり、このアノテーションによって変更されたインターフェースには抽象メソッドが 1 つだけ存在できることを示します。

/**
 * @機能インターフェース
 * これは関数型アノテーションです。このアノテーションによって変更されるインターフェースは、抽象メソッドを 1 つだけ宣言できます。*/


@機能インターフェース
パブリックインターフェースUserService{

    void 表示();

}

5. ラムダ式の原理

匿名内部クラスの本質は、コンパイル中にクラス ファイルを生成することです。 XXXXX$1クラス

パブリッククラスDemo01Lambda {

    パブリック静的voidメイン(String[] args) {
        // 新しいスレッドを開始します new Thread(new Runnable() {
            @オーバーライド
            パブリックボイド実行() {
                System.out.println("新しいスレッドで実行されたコード: "+Thread.currentThread().getName());
            }
        })。始める();
        System.out.println("メインスレッドのコード: " + Thread.currentThread().getName());
        System.out.println("---------------");
        /*new Thread(() -> { System.out.println("新しいスレッド ラムダ式..." +Thread.currentThread().getName()); })
                。始める();*/
    }
}

逆コンパイルツールを使って生成されたコードを表示することもできます。XJadツールを使って表示することもできます。

静的クラス Demo01Lambda$1
 Runnableを実装する
{

 パブリック void 実行()
 {
  System.out.println((new StringBuilder()).append("新しいスレッドで実行されたコード: " ).append(Thread.currentThread().getName()).toString());
 }

 デモ01ラムダ$1()
 {
 }
}

では、ラムダ式の原理とは何でしょうか?また、逆コンパイルツールを使ってチェックします

ラムダ式を含むクラス ファイルの場合、XJad を使用してエラーをチェックします。このとき、JDK に付属するツール javap を使用してバイトコードを逆アセンブルすることができます。

javap -c -p ファイル名.クラス

  • -c: コードを逆アセンブルすることを意味する
  • -p: すべてのクラスとメンバーを表示

分解の結果:

E:\workspace\OpenClassWorkSpace\JDK8Demo\target\classes\com\bobo\jdk\lambda>javap -c -p Demo03Lambda.class
「Demo03Lambda.java」からコンパイル
パブリッククラス com.bobo.jdk.lambda.Demo03Lambda {
  パブリック com.bobo.jdk.lambda.Demo03Lambda();
    コード:
       0: ロード_0
       1:invokespecial #1 // メソッド java/lang/Object."<init>":()V
       4: 戻る

  パブリック静的 void main(java.lang.String[]);
    コード:
       0:invokedynamic #2, 0 // InvokeDynamic #0:show:()Lcom/bobo/jdk/lambda/service/UserService;
       5:invokestatic #3 // メソッド goShow:(Lcom/bobo/jdk/lambda/service/UserService;)V
       8: 戻る

  パブリック静的 void goShow(com.bobo.jdk.lambda.service.UserService);
    コード:
       0: ロード_0
       1: 呼び出しインターフェース #4, 1 // インターフェースメソッド com/bobo/jdk/lambda/service/UserService.show:()V
       6: 戻る

  プライベート静的void lambda$main$0();
    コード:
       0: getstatic #5 // フィールド java/lang/System.out:Ljava/io/PrintStream;
       3: ldc #6 // 文字列 Lambda show メソッドが実行されます...
       5:invokevirtual #7 // メソッド java/io/PrintStream.println:(Ljava/lang/String;)V
       8: 戻る
}

この逆コンパイルされたソース コードには、静的メソッド lambda$main$0() があります。このメソッドは何を行うのでしょうか?デバッグで確認してみましょう:

上記の効果は次のように理解できます。

パブリッククラスDemo03Lambda {

    パブリック静的voidメイン(String[] args) {
        ....
    }

    プライベート静的void lambda$main$0();
        System.out.println("Lambda show メソッドが実行されました...");
    }
}

これをより直感的に理解するには、実行時に-Djdk.internal.lambda.dumpProxyClassesを追加します。このパラメータを追加すると、内部クラスコードがファイルに出力されます。

java -Djdk.internal.lambda.dumpProxyClasses実行するパッケージ名。クラス名

コマンド実行

E:\workspace\OpenClassWorkSpace\JDK8Demo\target\classes>java -Djdk.internal.lambda.dumpProxyClasses com.bobo.jdk.lambda.Demo03Lambda
Lambda の show メソッドが実行されます...


逆コンパイルされたコンテンツ:

この匿名内部クラスは UserService インターフェースを実装し、show() メソッドをオーバーライドしていることがわかります。 showメソッドでは、Demo03Lambda.lambda$main$0()が呼び出され、Lambda内のコンテンツが呼び出されることになります。

パブリッククラスDemo03Lambda {

    パブリック静的voidメイン(String[] args) {
        goShow(新しいUserService() {
            @オーバーライド
            パブリックボイドショー(){
                Demo03Lambda.lambda$main$0();
            }
        });
        System.out.println("-----------");
       
    }

    パブリック静的void goShow(UserService userService){
        ユーザーサービスを表示します。
    }

    プライベート静的void lambda$main$0();
        System.out.println("Lambda show メソッドが実行されました...");
    }
}

まとめ:

匿名内部クラスは、コンパイル時にクラス ファイルを生成します。

ラムダ式は、プログラムの実行時にクラスを形成します。

  1. 新しいメソッドがクラスに追加されます。このメソッドのメソッド本体は、ラムダ式内のコードです。
  2. また、匿名の内部クラスを形成し、インターフェースを実装し、抽象メソッドをオーバーライドします。
  3. インターフェース内のメソッドをオーバーライドすると、新しく生成されたメソッドが呼び出されます。

6. ラムダ式の省略形

ラムダ式の標準的な記述に基づいて、省略記号を使用するルールは次のとおりです。

  1. 括弧内のパラメータ型は省略できます
  2. 括弧内にパラメータが 1 つしかない場合は、括弧を省略できます。
  3. 中括弧内にステートメントが 1 つしかない場合は、中括弧、return キーワード、およびステートメントのセミコロンを省略できます。
パブリッククラスDemo05Lambda {

    パブリック静的voidメイン(String[] args) {
        goStudent((文字列名、整数年齢)->{
            名前+年齢+" 6666 ..."を返します。
        });
        // 省略形 goStudent((name,age)-> name+age+" 6666 ...");
        System.out.println("------");
        goOrder((文字列名)->{
            System.out.println("--->" + 名前);
            666を返します。
        });
        // 省略表記 goOrder(name -> {
            System.out.println("--->" + 名前);
            666を返します。
        });
        goOrder(名前 -> 666);
    }

    パブリック静的void goStudent(StudentService studentService){
        studentService.show("张三",22);
    }

    パブリック静的 void goOrder(OrderService orderService){
        orderService.show("Li Si");
    }
    
}

7. ラムダ式を使用するための前提条件

ラムダ式の構文は非常に簡潔ですが、気軽に使用できるわけではありません。ラムダ式を使用する際には、特に注意が必要な条件がいくつかあります。

  1. Lambdaを使用するには、メソッドパラメータまたはローカル変数の型がインターフェースである必要があります。
  2. インターフェースには抽象メソッドが 1 つだけあります (@FunctionalInterface)

8. ラムダクラスと匿名内部クラスの比較

ラムダクラスと匿名内部クラスの比較

1. 必要なタイプが異なる

  • 匿名内部クラスのタイプは、クラス、抽象クラス、インターフェースのいずれかです。
  • ラムダ式に必要な型はインターフェースでなければなりません

2. 抽象メソッドの数が異なる

  • 匿名内部クラスに必要なインターフェース内の抽象メソッドの数は任意です。
  • ラムダ式ではインターフェースに抽象メソッドが1つだけ必要です

3. 実施原則が異なる

  • 匿名内部クラスはコンパイル後にクラスを形成する
  • ラムダ式は、プログラムの実行時にクラスを動的に生成します。

ラムダ式の原理と例についての記事はこれで終わりです。ラムダ式についてさらに詳しく知りたい方は、123WORDPRESS.COM の過去の記事を検索するか、以下の関連記事を引き続きご覧ください。今後とも 123WORDPRESS.COM をよろしくお願いいたします。

以下もご興味があるかもしれません:
  • Javaのラムダ式に関連する操作についての簡単な説明
  • Java8 の新機能: ラムダ式の概要
  • Java ラムダ式を理解し、1 分で使い方を学ぶ方法
  • Java-ラムダ式の紹介はこの記事を読めば十分です
  • Java関数型プログラミングとラムダ式の詳細な説明

<<:  Ubuntu 18.04 システムでの Redis および phpredis 拡張機能のインストールと設定の詳細な説明

>>:  MySQL 8.0.18 インストール構成の最適化チュートリアル

推薦する

HTMLインライン要素とブロックレベル要素の基本概念と使用例

HTML タグには、インライン要素とブロックレベル要素の 2 種類があります。まず、インライン要素と...

Linux自動ログイン例の説明

インターネット上には、expect を使用して自動ログインを実現するスクリプトが多数存在しますが、明...

SSHのssh-keygenコマンドの基本的な使い方の詳細な説明

SSH 公開鍵認証は、SSH 認証方式の 1 つです。 SSH パスワードフリーのログインは公開鍵認...

CSS3 弾性拡張ボックスの詳細な説明

使用フレキシブル ボックスはフロントエンドの Web ページ レイアウトで重要な役割を果たしますが、...

HTMLを使用してシンプルなメールテンプレートを作成する

今日は、「ローテク」の問題について書きたいと思います。ちなみに、私は JavaScript Week...

面接でよく聞かれる Vue 修飾子 13 個

目次1. 怠惰な2.トリム3.番号4.停止5. キャプチャ6.自分7.一度8.予防する9.ネイティブ...

CSS と Bootstrap アイコンを使用して、上下にジャンプするインジケーター矢印のアニメーション効果を作成します。

ページが非常に長い場合は、下にさらにコンテンツがあることをユーザーに知らせるために矢印が必要になるこ...

mysql 8.0.15 winx64 解凍バージョン グラフィック インストール チュートリアル

システムをインストールした後、毎回いくつかのソフトウェアを再インストールする必要があります。ソフトウ...

WeChatミニプログラム公式顔認証の詳しい説明

ミニプログラムはユーザーの個人情報を収集してアップロードしましたが、拒否されました。こんにちは、ミニ...

W3C チュートリアル (6): W3C CSS アクティビティ

スタイル シートは、ドキュメントの表示方法、発音方法、または入力方法を記述します。スタイル シートは...

MySQL の垂直テーブルを水平テーブルに変換する方法と最適化のチュートリアル

1. 縦型テーブルと横型テーブル垂直テーブル: テーブル内のフィールドとフィールド値はキーと値の形式...

jsはテーブルの追加と削除の操作を動的に実装します

この記事の例では、jsでテーブルを動的に追加および削除するための具体的なコードを参考までに共有してい...

uniappの無痛トークンリフレッシュ方法の詳細な説明

フロントエンドがインターフェースを要求すると、バックエンドでインターフェースが定義されます。ステータ...

モバイルウェブサイトの開発に関するいくつかの結論

ウェブサイトのモバイル版には、少なくともいくつかの基本機能が必要です。 1. ページの適用性の問題:...