工業製造
産業用モノのインターネット | 工業材料 | 機器のメンテナンスと修理 | 産業プログラミング |
home  MfgRobots >> 工業製造 >  >> Industrial programming >> Java

Java ラムダ式

Java ラムダ式

この記事では、Java ラムダ式と、関数型インターフェース、汎用関数型インターフェース、およびストリーム API でのラムダ式の使用について、例を使用して学習します。

ラムダ式は、Java 8 で初めて導入されました。その主な目的は、言語の表現力を高めることです。

しかし、ラムダに入る前に、まず関数型インターフェースを理解する必要があります.


機能インターフェースとは?

Java インターフェースに抽象メソッドが 1 つだけ含まれている場合、それは機能インターフェースと呼ばれます。この 1 つのメソッドだけが、インターフェースの意図された目的を指定します。

たとえば、Runnable パッケージ java.lang のインターフェース; 1 つのメソッド、つまり run() のみを構成するため、関数型インターフェイスです。 .

例 1:Java で機能インターフェースを定義する

import java.lang.FunctionalInterface;
@FunctionalInterface
public interface MyInterface{
    // the single abstract method
    double getValue();
}

上記の例では、インターフェイス MyInterface には抽象メソッド getValue() が 1 つだけあります。したがって、これは機能的なインターフェースです。

ここでは、注釈 @FunctionalInterface を使用しています。 .アノテーションは、インターフェースが機能インターフェースであることを Java コンパイラーに強制的に示します。したがって、複数の抽象メソッドを持つことはできません。ただし、必須ではありません。

Java 7 では、機能インターフェースは単一抽象メソッドまたは SAM と見なされていました。 タイプ。 SAM は、一般的に Java 7 の匿名クラスで実装されました。

例 2:Java で匿名クラスを使用して SAM を実装する

public class FunctionInterfaceTest {
    public static void main(String[] args) {

        // anonymous class
        new Thread(new Runnable() {
            @Override
            public void run() {
                System.out.println("I just implemented the Runnable Functional Interface.");
            }
        }).start();
    }
}

出力 :

I just implemented the Runnable Functional Interface.

ここで、無名クラスをメソッドに渡すことができます。これは、Java 7 でより少ないコードでプログラムを作成するのに役立ちます。ただし、構文は依然として難しく、多くの余分なコード行が必要でした。

Java 8 は、さらに一歩進んで SAM の能力を拡張しました。関数型インターフェースにはメソッドが 1 つしかないことがわかっているので、引数として渡すときにそのメソッドの名前を定義する必要はありません。ラムダ式はまさにそれを可能にします。


ラムダ式の概要

ラムダ式は、本質的に、匿名または名前のないメソッドです。ラムダ式は単独では実行されません。代わりに、機能インターフェースによって定義されたメソッドを実装するために使用されます。

Java でラムダ式を定義する方法

Java でラムダ式を定義する方法は次のとおりです。

(parameter list) -> lambda body

new 演算子 (-> ) は、アロー演算子またはラムダ演算子として知られています。現時点では、構文が明確でない可能性があります。いくつかの例を見てみましょう。

次のようなメソッドがあるとします:

double getPiValue() {
    return 3.1415;
}

ラムダ式を使用してこのメ​​ソッドを次のように記述できます。

() -> 3.1415

ここで、メソッドにはパラメーターがありません。したがって、演算子の左側には空のパラメーターが含まれます。右側は、ラムダ式のアクションを指定するラムダ本体です。この場合、値 3.1415 を返します。


ラムダ ボディのタイプ

Java では、ラムダ本体には 2 つのタイプがあります。

<強い>1.表情がひとつの身体

() -> System.out.println("Lambdas are great");

このタイプのラムダ本体は式本体として知られています。

<強い>2.コードのブロックで構成される本文。

() -> {
    double pi = 3.1415;
    return pi;
};

このタイプのラムダ本体は、ブロック本体として知られています。ブロック本体により、ラムダ本体に複数のステートメントを含めることができます。これらのステートメントは中括弧で囲まれており、中括弧の後にセミコロンを追加する必要があります.

注意 :ブロック本体の場合、本体が値を返す場合は return ステートメントを使用できます。ただし、式本体には return ステートメントは必要ありません。


例 3:ラムダ式

ラムダ式を使用して Pi の値を返す Java プログラムを書きましょう。

前述のとおり、ラムダ式は単独では実行されません。むしろ、機能インターフェースによって定義された抽象メソッドの実装を形成します。

したがって、最初に機能インターフェースを定義する必要があります。

import java.lang.FunctionalInterface;

// this is functional interface
@FunctionalInterface
interface MyInterface{

    // abstract method
    double getPiValue();
}

public class Main {

    public static void main( String[] args ) {

    // declare a reference to MyInterface
    MyInterface ref;
    
    // lambda expression
    ref = () -> 3.1415;
    
    System.out.println("Value of Pi = " + ref.getPiValue());
    } 
}

出力 :

Value of Pi = 3.1415

上記の例では、


パラメータ付きラムダ式

これまで、パラメーターなしでラムダ式を作成してきました。ただし、メソッドと同様に、ラムダ式にもパラメーターを含めることができます。たとえば、

(n) -> (n%2)==0

ここで、括弧内の変数 n は、ラムダ式に渡されるパラメーターです。ラムダ本体はパラメーターを受け取り、それが偶数か奇数かをチェックします。

例 4:パラメータでラムダ式を使用する

@FunctionalInterface
interface MyInterface {

    // abstract method
    String reverse(String n);
}

public class Main {

    public static void main( String[] args ) {

        // declare a reference to MyInterface
        // assign a lambda expression to the reference
        MyInterface ref = (str) -> {

            String result = "";
            for (int i = str.length()-1; i >= 0 ; i--)
            result += str.charAt(i);
            return result;
        };

        // call the method of the interface
        System.out.println("Lambda reversed = " + ref.reverse("Lambda"));
    }

}

出力 :

Lambda reversed = adbmaL

汎用機能インターフェース

これまで、1 つのタイプの値のみを受け入れる関数型インターフェースを使用してきました。たとえば、

@FunctionalInterface
interface MyInterface {
    String reverseString(String n);
}

上記の機能インターフェースは String のみを受け入れます String を返します .ただし、関数インターフェイスを汎用にすることで、あらゆるデータ型を受け入れることができます。ジェネリックについてよくわからない場合は、Java ジェネリックにアクセスしてください。

例 5:ジェネリック関数型インターフェイスとラムダ式

// GenericInterface.java
@FunctionalInterface
interface GenericInterface<T> {

    // generic method
    T func(T t);
}

// GenericLambda.java
public class Main {

    public static void main( String[] args ) {

        // declare a reference to GenericInterface
        // the GenericInterface operates on String data
        // assign a lambda expression to it
        GenericInterface<String> reverse = (str) -> {

            String result = "";
            for (int i = str.length()-1; i >= 0 ; i--)
            result += str.charAt(i);
            return result;
        };

        System.out.println("Lambda reversed = " + reverse.func("Lambda"));

        // declare another reference to GenericInterface
        // the GenericInterface operates on Integer data
        // assign a lambda expression to it
        GenericInterface<Integer> factorial = (n) -> {

            int result = 1;
            for (int i = 1; i <= n; i++)
            result = i * result;
            return result;
        };

        System.out.println("factorial of 5 = " + factorial.func(5));
    }
}

出力 :

Lambda reversed = adbmaL
factorial of 5 = 120

上記の例では、GenericInterface という名前の汎用機能インターフェースを作成しました。 . func() という名前の汎用メソッドが含まれています .

ここで、Main クラス内で、


ラムダ式とストリーム API

新しい java.util.stream パッケージが JDK8 に追加され、Java 開発者は Lists のようなコレクションの検索、フィルター、マップ、縮小、または操作などの操作を実行できます。 .

たとえば、データのストリームがあります (この場合は List String の ) ここで、各文字列は国名とその国の場所の組み合わせです。これで、このデータ ストリームを処理して、ネパールから場所のみを取得できます。

このため、ストリーム API とラムダ式を組み合わせて、ストリーム内で一括操作を実行できます。

例 6:Stream API でラムダを使用するデモ

import java.util.ArrayList;
import java.util.List;

public class StreamMain {

    // create an object of list using ArrayList
    static List<String> places = new ArrayList<>();

    // preparing our data
    public static List getPlaces(){

        // add places and country to the list
        places.add("Nepal, Kathmandu");
        places.add("Nepal, Pokhara");
        places.add("India, Delhi");
        places.add("USA, New York");
        places.add("Africa, Nigeria");

        return places;
    }

    public static void main( String[] args ) {

        List<String> myPlaces = getPlaces();
        System.out.println("Places from Nepal:");
        
        // Filter places from Nepal
        myPlaces.stream()
                .filter((p) -> p.startsWith("Nepal"))
                .map((p) -> p.toUpperCase())
                .sorted()
                .forEach((p) -> System.out.println(p));
    }

}

出力 :

Places from Nepal:
NEPAL, KATHMANDU
NEPAL, POKHARA

上記の例では、次のステートメントに注目してください。

myPlaces.stream()
        .filter((p) -> p.startsWith("Nepal"))
        .map((p) -> p.toUpperCase())
        .sorted()
        .forEach((p) -> System.out.println(p));

ここでは、filter() のようなメソッドを使用しています。 、 map()forEach() ストリーム API の。これらのメソッドはラムダ式を入力として受け取ることができます。

上記で学んだ構文に基づいて、独自の式を定義することもできます。これにより、上記の例で見たようにコード行を大幅に減らすことができます。


Java

  1. C# インターフェイス
  2. Java オペレーター
  3. Java 式、ステートメント、およびブロック
  4. Java インターフェイス
  5. Java try-with-resources
  6. Java アノテーション
  7. Java のインターフェイスと抽象クラス:違いは何ですか?
  8. Java-正規表現
  9. Java-インターフェース
  10. Java 9 - プライベート インターフェイス メソッド
  11. Java 8 - ラムダ式