[Java基本文法]Javaのラムダ式を詳しく説明する

1はじめに

  • ラムダ式はJavaSE8の重要な新機能です
  • ラムダ式を使用すると、関数型インターフェースを式に置き換えることができます
  • ラムダ式は、メソッドと同様に、通常のパラメーターリストとそれらのパラメーターを使用する本体を提供します
  • ラムダ式は無名関数と考えることができます、数学のラムダ計算にちなんで名付けられた、クロージャとも呼ばれます
  • ラムダ式を使用すると、関数をメソッドパラメーターとして使用できます

2.ラムダ式の構文

基本形式:ラムダ式は、パラメーター、->シンボル、メソッド本体の3つの部分で構成されます

(参数列表)->{
    
    方法体}

補充:

  • ラムダ式は0個以上のパラメーターを持つことができます
  • パラメータのタイプは、明示的に宣言することも宣言しないこともでき、JVMによって暗黙的に推測されます。(int a)たとえば(a)、同じ効果があります。
  • パラメータが1つだけで、タイプを推測できる場合は、たとえば、(a)と同じa効果で括弧を省略できます。
  • ラムダ式のメソッド本体にステートメントが1つしかない場合は、中括弧を省略できます
  • ラムダ式のメソッド本体にステートメントが1つだけあり、それが戻り値である場合は、returnを省略できます。

コード例:

// 不需要参数,返回值为 2
()->2
    
// 接收一个参数(数字类型),返回值为其2倍的值
x->2*x

// 接收两个参数(数字类型),并返回它们的和
(x,y)->x+y
    
// 接收两个 int 类型参数,返回它们的乘积
(int x,int y)->x*y

// 接收一个 String 对象,并在控制台打印
(String s)->System.out.println(s)

3.機能インターフェース

もしもインターフェイスには抽象メソッドが1つしかないため、このようなインターフェイスは単一インターフェイスと呼ばれます。JDK8以降、JavaはLambda式を使用します。単一のインターフェースは機能インターフェースと呼ばれます

知らせ:

  • 抽象メソッドが1つしかない場合、インターフェースは機能インターフェースです。
  • インターフェイスで@FunctionInterfaceアノテーションと、コンパイラは機能インターフェイスの定義に従ってインターフェイスを必要とするため、このインターフェイスは1つの抽象メソッドしか持てません。それを超えると、プログラムはコンパイル時にエラーを報告します。

サンプルコード:

@functionInterface
interface A{
    
    
    void test();
}

4.Lamdba式の使用

次に、ラムダ式の使用法を示します

// 无返回值无参数 
@FunctionalInterface interface NoParameterNoReturn {
    
     void test(); }
// 无返回值一个参数 
@FunctionalInterface interface OneParameterNoReturn {
    
     void test(int a); }
// 无返回值多个参数 
@FunctionalInterface interface MoreParameterNoReturn {
    
     void test(int a,int b); }
// 有返回值无参数 
@FunctionalInterface interface NoParameterReturn {
    
     int test(); }
// 有返回值一个参数 
@FunctionalInterface interface OneParameterReturn {
    
     int test(int a); }
// 有返回值多参数 
@FunctionalInterface interface MoreParameterReturn {
    
     int test(int a,int b); }

public class TestDemo {
    
     
    public static void main(String[] args) {
    
     
        NoParameterNoReturn noParameterNoReturn = ()->{
    
     System.out.println("无参数无返回值"); };
        noParameterNoReturn.test(); 
        
        OneParameterNoReturn oneParameterNoReturn = (int a)->{
    
     System.out.println("无参数一个返回值:"+ a); };
        oneParameterNoReturn.test(10); 
        
        MoreParameterNoReturn moreParameterNoReturn = (int a,int b)->{
    
     System.out.println("无返回值多个参数:"+a+" "+b); };
        moreParameterNoReturn.test(20,30); 
        
        NoParameterReturn noParameterReturn = ()->{
    
     System.out.println("有返回值无参数!"); return 40; };
        //接收函数的返回值 
        int ret = noParameterReturn.test(); 
        System.out.println(ret); 
        
        OneParameterReturn oneParameterReturn = (int a)->{
    
     System.out.println("有返回值有参数!"); return a; };
        ret = oneParameterReturn.test(50); 
        System.out.println(ret); 
        
        MoreParameterReturn moreParameterReturn = (int a,int b)->{
    
     System.out.println("有返回值多个参数!"); return a+b; };
        ret = moreParameterReturn.test(60,70);
		System.out.println(ret); 
    } 
}

5.変数キャプチャ

5.1はじめに

変数キャプチャは、Javaのローカルクラスと匿名クラスの両方に存在します

ラムダ式にも変数キャプチャがあるため、変数キャプチャとは何かを理解して初めて、ラムダ式のスコープをよりよく理解できます。

5.2匿名内部クラスの変数キャプチャ

class A {
    
     
    public void func(){
    
     
        System.out.println("func()"); 
    } 
}
public class TestDemo {
    
     
    public static void main(String[] args) {
    
     
        int a = 100; 
        new Test(){
    
     
            @Override public void func() {
    
     
                System.out.println("我是内部类,且重写了func这个方法!");
                System.out.println("我是捕获到变量 a == "+a +" 我是一个常量,或者是一个没有改变过值的变量!"); 
            } 
        }; 
    } 
}

上記のコードの変数aはキャプチャされた変数です。この変数は、finalによって変更されるか、匿名内部クラスで使用されるときに変数が変更されないようにする必要があります。変更されると、コンパイルエラーが発生します。

5.3ラムダ変数のキャプチャ

ラムダでは可変キャプチャも可能です

@FunctionalInterface interface A {
    
     
    void test(); 
}
public static void main(String[] args) {
    
     
    int a = 10; 
    NoParameterNoReturn noParameterNoReturn = ()->{
    
    
        // a = 99; 如果修改a,则会报错 
        System.out.println("捕获变量:"+a); 
    };
    noParameterNoReturn.test(); 
}

6.コレクションでのLambdaの使用

LambdaコレクションクラスとJavaコレクションクラスをより適切に連携させるために、Lambda式とドッキングするためのいくつかの新しいインターフェイスがコレクションに追加されました。

対応するインターフェース メソッドを追加
コレクション removeIf()、、、、、spliterator()_ stream()_ parallelStream()_forEach()
リスト replaceAll()sort()
地図 getDefault()、、、、、、、、、、、forEach()_ replaceAll()_ putIfAbsent()_ remove()_ replace()_ computeIfAbsent()_ computeIfPresent()_ compute()_merge()

補充:

コレクションのforEach()メソッドはインターフェースからjava.lang.Interable継承されます

6.1収集インターフェース

forEach()メソッドを使用したデモンストレーション

forEach()ソースコード: ここに画像の説明を挿入

コード例:匿名の内部クラスの使用

public class TestDemo{
    
    
    public static void main(String[] args) {
    
    
        List<String> list=new ArrayList<>();
        list.add("aaa");
        list.add("bbb");
        list.add("ccc");
        list.forEach(new Consumer<String>() {
    
    
            @Override
            public void accept(String s) {
    
    
                System.out.print(s+" ");
            }
        });
    }
}
// 结果为:aaa bbb ccc

コード例: Lambdaの使用

public class TestDemo{
    
    
    public static void main(String[] args) {
    
    
        List<String> list=new ArrayList<>();
        list.add("aaa");
        list.add("bbb");
        list.add("ccc");
        list.forEach(s -> System.out.print(s+" "));
    }
}
// 结果为:aaa bbb ccc

6.2リストインターフェース

sort()メソッドを使用したデモンストレーション

sort()ソースコード: ここに画像の説明を挿入

コード例:匿名の内部クラスの使用

public class TestDemo{
    
    
    public static void main(String[] args) {
    
    
        List<String> list=new ArrayList<>();
        list.add("aaa");
        list.add("bbb");
        list.add("ccc");
        list.sort(new Comparator<String>() {
    
    
            @Override
            public int compare(String o1, String o2) {
    
    
                return o1.compareTo(o2);
            }
        });
        System.out.println(list);
    }
}
// 结果为:[aaa, bbb, ccc]

コード例: Lambdaの使用

public class TestDemo{
    
    
    public static void main(String[] args) {
    
    
        List<String> list=new ArrayList<>();
        list.add("aaa");
        list.add("bbb");
        list.add("ccc");
        list.sort((String o1,String o2)->o1.compareTo(o2));
        System.out.println(list);
    }
}
// 结果为:[aaa, bbb, ccc]

6.3マップインターフェース

HashMapのforEach()メソッドを使用してデモンストレーションします

HashMap 的 forEach()ソースコード:

ここに画像の説明を挿入

コード例:匿名の内部クラスの使用

public class TestDemo{
    
    
    public static void main(String[] args) {
    
    
        Map<Integer,String> map=new HashMap<>();
        map.put(1,"aaa");
        map.put(2,"222");
        map.put(3,"333");
        map.forEach(new BiConsumer<Integer, String>() {
    
    
            @Override
            public void accept(Integer integer, String s) {
    
    
                System.out.println("Key="+integer+" Value="+s);
            }
        });
    }
}
/** 结果为:
Key=1 Value=aaa
Key=2 Value=222
Key=3 Value=333
*/

コード例: Lambdaの使用

public class TestDemo{
    
    
    public static void main(String[] args) {
    
    
        Map<Integer,String> map=new HashMap<>();
        map.put(1,"aaa");
        map.put(2,"222");
        map.put(3,"333");
        map.forEach((Integer integer,String s)->
                System.out.println("Key="+integer+" Value="+s));
    }
}
/** 结果为:
Key=1 Value=aaa
Key=2 Value=222
Key=3 Value=333
*/

7.ラムダ式の長所と短所

アドバンテージ:

  • シンプルなコード、迅速な開発
  • 便利な関数型プログラミング
  • 並列化が簡単
  • Javaは収集操作を改善するためにLambdaを導入します

欠点:

  • コードの可読性が低い
  • 非並列コンピューティングでは、多くの計算で従来のforループのような高性能が得られない場合があります

おすすめ

転載: blog.csdn.net/weixin_51367845/article/details/122031877