lamda表現の使用と例

8352 ワード

まず、なぜlambandを導入したのですか?
関数式プログラミング言語では、関数は1等公民であり、それらは独立して存在することができ、変数に割り当てたり、彼らをパラメータとして他の関数に渡すことができます.JavaScriptは最も典型的な関数式プログラミング言語です.ここをクリックすると、JavaScriptという関数言語の利点が分かります.関数式言語は、従来のプログラミング方法に比べて多くの利点を持つ強力な機能を提供しています.クローズドは呼び出し可能なオブジェクトです.これらの情報は、作成されたスコープからの情報を記録しています.Javaが現在提供している最も近いクローズドの概念はLamband表現であり、クローズドとLambada表現との間には著しい違いがあるが、少なくともLambada表現はクローズドに優れた代替表現である.
Steeve Yeggは辛辣でユーモラスなブログ記事で、Javaの世界がいかに厳格に名詞を中心としているかを描いています.
Lambada表式はJavaに欠落した関数式プログラミングの特徴を追加しました.私たちは関数を一等国民として扱うことができます.完全ではありませんが、ランダとクローズドの違いはすぐに分かります.しかし、限りなくクローズドに近づいています.クラスの関数をサポートする言語では、Lamban表現の種類が関数となります.しかし、Javaでは、Lamda表現は対象であり、彼らは特別なオブジェクトタイプの関数式インターフェースに依存しなければならない.
 
インターフェースの実現
まず一番よく使うのはimplementsです.
このような方式は一つの実現方法(関数式インターフェース)があるだけではあまり便利ではないです.この時は内部の方式を使うことができます.
また関数式インターフェースに言及しました.
Javaでは、マーカータイプのインターフェースは、方法または属性宣言がないインターフェースであり、簡単にはマーカーインターフェースは空インターフェースである.同様に、関数インターフェースは抽象的な方法宣言のみを含むインターフェースである.java.lang.Runnable 関数式インターフェースです.Runnableインターフェースで一つの方法だけを宣言しました.  void run()、同様に、Action Listenerインターフェースも関数式インターフェースであり、匿名の内部クラスを使用して関数式インターフェースのオブジェクトを実装し、Lamber表現があり、この方法は簡略化される.
@Funtional Interface は、Java 8が新しく加入したインターフェースであり、このインターフェースタイプ宣言がJava言語規範に基づいて定義されている関数式インターフェースであることを示すためのインターフェースである.
Callable callable1 = new Callable() {
    public Integer call() throws Exception {
        return new Random().nextInt(100);
    }
};

new Thread(new Runnable() {
    @Override
    public void run() {
        System.out.println("Before Java8, too much code for too little to do");
    }
}).start();
二つのスレッドの使い方は典型的な代表ですが、このようにコードを書くと複雑で本当に面白くないです.この場合はlamda表現で最適化できます.
Callable callable = () -> new Random().nextInt(100);

new Thread( () -> System.out.println("In Java8, Lambda expression rocks !!") ).start();
「-」{}を使えば内部クラスが簡単に実現できます.  (argument) -> (body)Lamda表現の構造:
  • 個のLamban表現は、0個以上のパラメータ
  • を有することができる.
  • パラメータのタイプは、明示的に宣言されてもよく、文脈に基づいて推論されてもよい.例えば、(int a)(a)と同じ効果です.
  • すべてのパラメータは、括弧内に含まれている必要があります.パラメータ間はカンマで区切られています.(a, b) または  (int a, int b) または  (String a, int b, float c)
  • 丸かっこは、パラメータセットが空です.例えば、() -> 42
  • は、パラメータが一つしかなく、そのタイプが導出できる場合、括弧()は省略されてもよい.例えば、a -> return a*a
  • Lamband表現の本体は、ゼロまたは複数のステートメント
  • を含むことができる.
  • Lamda表現の主体が一つの語句しかない場合、括弧{}は省略できます.匿名関数の戻りタイプは、この本体表現と一致する
  • .
  • Lamda表現の本体に複数の語句が含まれている場合、式は括弧{}に含まれる必要があります.匿名関数の戻りのタイプは、コードブロックの戻りのタイプと一致しており、戻りがなければ空
  • である.
     
    バンドパラメータの例:
    文字列リストをカスタムコンパレータで並べ替える場合、Java 7の書き方は以下の通りです. 
    // JDK7        
    List list = Arrays.asList("I", "love", "you", "too");
    Collections.sort(list, new Comparator(){//    
        @Override
        public int compare(String s1, String s2){//    
            if(s1 == null)
                return -1;
            if(s2 == null)
                return 1;
            return s1.length()-s2.length();
        }
    });
    上記のコードは、内部クラスによってCompratorインターフェースのcompar()を積載し、比較論理を実現します.Lambda式を採用すると以下のように簡単に書くことができます.
    // JDK8 Lambda     
    List list = Arrays.asList("I", "love", "you", "too");
    Collections.sort(list, (s1, s2) ->{//         
        if(s1 == null)
            return -1;
        if(s2 == null)
            return 1;
        return s1.length()-s2.length();
    });
    上記のコードは匿名の内部クラスの役割と同じです.インターフェース名とメソッド名を省略したほか、コードの中でパラメータテーブルの種類も省略しました.これはjavacのタイプ推定メカニズムのおかげで、コンパイラはコンテキスト情報からパラメータのタイプを推測できます.もちろん、推論が失敗した場合もあります.この場合は手動でパラメータのタイプを指定する必要があります.Javaは強型言語であり、各変数とオブジェクトには明確なタイプが必要です.
    いくつかの例:
    Lamberを使用できる根拠は、それぞれの関数インターフェース(関数インターフェースとは、内部に抽象的な方法しかないインターフェースのこと)が必要であると考えられているかもしれません.この点はJavaが強い言語と一致しています.つまり、コードのどこでもわがままにLamband表現を書いてはいけません.実はLamberのタイプは対応関数インターフェースのタイプです.Lambda表式のもう一つの根拠は、タイプ推定機構であり、コンテキスト情報が十分である場合、コンパイラは、明示的な指名を必要とせずにパラメータテーブルのタイプを推定することができる.Lambadaはより多くの合法的な書き方を表しています.
    // Lambda        
    Runnable run = () -> System.out.println("Hello World");// 1
    ActionListener listener = event -> System.out.println("button clicked");// 2
    Runnable multiLine = () -> {// 3    
        System.out.print("Hello");
        System.out.println(" Hoolee");
    };
    BinaryOperator add = (Long x, Long y) -> x + y;// 4
    BinaryOperator addImplicit = (x, y) -> x + y;// 5     
    上記のコードの中で、1は無参照関数の略記を示しています.2には、参照関数の簡略化とタイプ推定メカニズムが示されている.3はコードブロックの書き方です.4および5は再びタイプ推定機構を示した. 
    まとめと比較:
    ()->が見られます  new Callable(){}のようなnew出てくるインターフェースが必要になりました.
    {}本来実現すべき方法名も省略されています.大括弧の中に方法体を書き出せばいいです.
    WIKI   
    匿名クラスとLamda表現を使う大きな違いはキーワードの使用にあります.匿名クラスに対して、キーワード  this 匿名クラスとして解読し、ランバー表現に対してキーワード  this Lambandの外部カテゴリについて解説します.
    匿名の内部クラスは独立したクラスにコンパイルされますが、lambadaは所在の種類のプライベートメソッドにコンパイルされます.
    Lambda表現と匿名クラスの別の違いは、両者のコンパイル方法にある.JavaコンパイラはLambada式をコンパイルして、彼らをクラスの中の私有関数に転化します.それはJava 7に新しく加えられたものを使います.  invokedynamic コマンドを動的に結合する方法は、JavaがどのようにLamban表現をバイトコードにコンパイルするかについて、Tal Weissは素晴らしい文章を書いています.
    リストのループ
    forとforeachは私達の数年を伴っています.lamda式でも簡単に書きました.
    List features = Arrays.asList("Lambdas", "Default Method", "Stream API", "Date and Time API");
    for (String feature : features) {
        System.out.println(feature);
    }
    これは普通のforeach方法です.次はlamda版に書き換えます.
    // Java 8  :
    List features = Arrays.asList("Lambdas", "Default Method", "Stream API", "Date and Time API");
    features.forEach(n -> System.out.println(n));
     
    //   Java 8        ,     ::        ,
    //     C++         
    features.forEach(System.out::println);
    両方の方法は遍歴効果がありますが、私はまだfor eachの使い方に慣れています. 
    ループして論理処理を行う
    私たちは断言関数式インターフェースを使ってテストを作成し、すべてのテストを通過する要素をプリントします.そうすると、Lamda式を使っていくつかの論理を規定し、これを基礎として成果があります.
    import java.util.Arrays;
    import java.util.List;
    import java.util.function.Predicate;
    
    public class Main {
    
    public static void main(String [] a)  {
    
        List list = Arrays.asList(1, 2, 3, 4, 5, 6, 7);
    
        System.out.println("Print all numbers:");
        evaluate(list, (n)->true);
    
        System.out.println("Print no numbers:");
        evaluate(list, (n)->false);
    
        System.out.println("Print even numbers:");
        evaluate(list, (n)-> n%2 == 0 );
    
        System.out.println("Print odd numbers:");
        evaluate(list, (n)-> n%2 == 1 );
    
        System.out.println("Print numbers greater than 5:");
        evaluate(list, (n)-> n > 5 );
    
    }
    
    public static void evaluate(List list, Predicate predicate) {
        for(Integer n: list)  {
            if(predicate.test(n)) {
                System.out.println(n + " ");
            }
        }
    }
    
    }   
    出力:
    Print all numbers: 1 2 3 4 5 6 7 
    Print no numbers: 
    Print even numbers: 2 4 6 
    Print odd numbers: 1 3 5 7 
    Print numbers greater than 5: 6 7
    Lambda表式を用いて数値中の各要素の二乗を印刷したが,stream()法を用いて従来の配列をストリームに変換することに注意した.Java 8は、いくつかの超棒ストリームAPIを追加した.java.util.stream.Stream インターフェースには多くの有用な方法が含まれており,Lamband表現と結合して不思議な効果をもたらす.我々はLamber表現を行います.  x -> x*x map()方法に伝えて、この方法は流れのすべての要素に作用します.その後、私達はforEach方法を使ってデータ中のすべての要素を印刷します.
    //Old way:
    List list = Arrays.asList(1,2,3,4,5,6,7);
    for(Integer n : list) {
        int x = n * n;
        System.out.println(x);
    }
    
    //New way:
    List list = Arrays.asList(1,2,3,4,5,6,7);
    list.stream().map((x) -> x*x).forEach(System.out::println);
     
    与えられた値の各要素の二乗後の総和を計算します.なお、Lamda表式は一つの文だけでこの機能を達成することができます.これもMapReduceの一次例です.私たちはmap()を使って各要素に平方を求め、reduce()を使ってすべての要素を一つの数値に計算します.
     
    //Old way:
    List list = Arrays.asList(1,2,3,4,5,6,7);
    int sum = 0;
    for(Integer n : list) {
        int x = n * n;
        sum = sum + x;
    }
    System.out.println(sum);
    
    //New way:
    List list = Arrays.asList(1,2,3,4,5,6,7);
    int sum = list.stream().map(x -> x*x).reduce((x,y) -> x + y).get();
    System.out.println(sum);
     
    ここに来たら、Javaでのlamda表現の応用はこれぐらいです.
     
    java 8についての知識があります.Optionalを見てください. Prodcate Consmer Stream
     
    勉強は私を満足させます