Java 8特性詳細(一)Lambda

13700 ワード

なぜlambda式を使うのか


関数インタフェースから


Functional Interface(関数インタフェース)を理解することはJava 8 lambda式を学ぶ上で重要なポイントです.
関数インタフェースの定義は簡単です.どのインタフェースも、唯一の抽象的な方法しか含まれていない場合は、関数インタフェースです.関数インタフェースの場合、lambda式でインタフェースのオブジェクトを作成できます.
コンパイラが関数インタフェースの要件を満たすインタフェース、すなわち抽象的な方法が1つしかないことを保証するのに役立ちます.Java 8では@FunctionalInterface注記が提供されています.簡単な例を挙げると、RunnableインタフェースはFIで、次はソースコードです.
@FunctionalInterface
public interface Runnable {
    public abstract void run();
}

@FunctionalInterface注釈を使用しても、必須ではありません.しかし、注釈を使用すると、コードがより明確に見えます.

Lambda式の文法糖


こうぶん糖


Javaのlambda式のフォーマット:パラメータ、矢印->、式.Lambda式の構文糖を実証するために,例としてComparatorを用いた.Java 8の前に匿名の内部クラスを利用して実現することができます.
public static List compareTest1(){
    List wordList = Arrays.asList("lianggzone", "spring", "summer", "autumn", "winter");
    wordList.sort(new Comparator() {
        @Override
        public int compare(String w1, String w2) {
            return Integer.compare(w1.length(), w2.length());
        }
    });
    return wordList;        
}

Comparatorは関数インタフェースであり,Lambda式で実現できる.Lambda式は匿名の方法に似ていますが、カッコ内のパラメータリストとカッコ内のコードが->区切られています.
public static List compareTest2(){
    List wordList = Arrays.asList("lianggzone", "spring", "summer", "autumn", "winter");
    wordList.sort((String w1, String w2) -> {
        return Integer.compare(w1.length(), w2.length());
    });
    return wordList;        
}

lambda式のパラメータタイプが導出可能である場合、それらのタイプを省略することができる.
public static List compareTest3(){
    List wordList = Arrays.asList("lianggzone", "spring", "summer", "autumn", "winter");
    wordList.sort((w1, w2) -> {
        return Integer.compare(w1.length(), w2.length()); 
    });
    return wordList;        
}

lambda式のコードブロックがreturnの後に式が続くだけである場合、さらに簡略化することもできる.
public static List compareTest4(){
    List wordList = Arrays.asList("lianggzone", "spring", "summer", "autumn", "winter");
    wordList.sort((w1, w2) ->  Integer.compare(w1.length(), w2.length()));
    return wordList;        
}

メソッドにパラメータが1つしか含まれていない場合、そのパラメータのタイプを導出することができ、カッコを省略することもできます.
public static List compareTest5(){
    List wordList = Arrays.asList("lianggzone", "spring", "summer", "autumn", "winter");
    wordList.forEach(word ->  System.out.println(word));
    return wordList;        
}

別の独立したスレッドでいくつかの論理を実行する場合、通常、Runableインタフェースを実装するクラスのrunメソッドにコードが配置されます.
public static void runnableTest1(){
    Executors.newSingleThreadExecutor().execute(new Runnable() {    
        @Override
        public void run() {
            for (int i = 0; i < 10; i++) {
                System.out.println(i);
            }
        }
    });    
}

Lambda式にパラメータがない場合は、パラメータを含まない方法のように、空のカッコのペアを提供することができます.
public static void runnableTest2(){
    Executors.newSingleThreadExecutor().execute(() -> {
        for (int i = 0; i < 10; i++) {
            System.out.println(i);
        }
    });    
}

注意点
  • lambda式は戻りタイプを実行し、コンテキストに基づいて押し出され、戻りタイプを設定する必要はありません.
  • lambda式では、一部のブランチでのみ値が返されます.これはエラーです.

  • メソッド参照


    場合によっては、lambda式のコードは単純なメソッド呼び出しにすぎません.この場合、lambda式はメソッド参照にさらに簡略化されます.::オペレータは、メソッド名とオブジェクトまたはクラスの名前を区切ります.

    オブジェクトおぶじぇくと:インスタンスオブジェクトれいとおぶじぇくと


    Java 8の前に、リストの内容を印刷します.通常はそうします.
    public static void print1(){
        List wordList = Arrays.asList("lianggzone", "spring", "summer", "autumn", "winter");
        wordList.forEach(new Consumer() {
            @Override
            public void accept(String word) {
                System.out.println(word);
            }
        });    
    }

    Consumerは関数インタフェースであるため,lambda式を改造した.
    public static void print2(){
        List wordList = Arrays.asList("lianggzone", "spring", "summer", "autumn", "winter");
        wordList.forEach(word -> System.out.println(word));        
    }

    メソッド参照に変更すると、式System.out::println、word->Systemに等しい.out.println(word).
    public static void print3(){
        List wordList = Arrays.asList("lianggzone", "spring", "summer", "autumn", "winter");
        wordList.forEach(System.out::println);    
    }

    クラス:インスタンスオブジェクト[くらす:れいとおぶじぇくと]


    たとえば、大文字と小文字を区別せずに文字列をソートします.
    public static String[] sort1(){
        String[] words = new String[]{"lianggzone", "spring", "summer", "autumn", "winter"};
        Arrays.sort(words, (x, y) -> x.compareToIgnoreCase(y));
        return words;
    }

    メソッド参照に変更すると、式:String::compareToIgnoreCase(x,y)->x.compareToIgnoreCase(y)に等しく、第1のパラメータがメソッドを実行するオブジェクトになります.
    public static String[] sort2(){
        String[] words = new String[]{"lianggzone", "spring", "summer", "autumn", "winter"};
        Arrays.sort(words, String::compareToIgnoreCase);
        return words;
    }

    オブジェクト:静的メソッド静的メソッド


    たとえば、コレクションをソートします.
    public static List sortList1(){
        List wordList = Arrays.asList(21, 53);
        wordList.sort((w1, w2) -> Integer.compare(w1, w2));
        return wordList;
    }

    メソッド参照に変更すると、式:Integer::compare、(w 1,w 2)->Integerに等しい.compare(w 1,w 2)では,第1パラメータが実行方法の対象となる.
    public static List sortList2(){
        List wordList = Arrays.asList(21, 53);
        wordList.sort(Integer::compare);
        return wordList;
    }

    コンストラクタリファレンス

    // lambda
    words.stream().map(word -> {
        return new StringBuilder(word);
    });
    // constructor reference
    words.stream().map(StringBuilder::new);

    変数スコープ


    Java 8以前は内部クラスはfinalのローカル変数にしかアクセスできなかったが,lambda式に適応するためにJava 8はこの制限を緩和し,変数が実際に可変でなければよい.
    public static void effectivelyFinal(){
        int a = 100;
        Executors.newSingleThreadExecutor().execute(() -> {
            System.out.println(a);
        });    
    }

    Lambda式では、参照される変数の値は変更できません.この制約を行うには、lambda式の変数がスレッドで安全ではないため、理由があります.

    インタフェースの静的メソッド


    Java 8から、インタフェースにも静的な方法があります.この文法があれば,インタフェースに関連するヘルプメソッドをインタフェースに直接定義することができる.
    たとえばFunctionインタフェースは、ファクトリメソッドindentity()を定義します.値を割り当てるターゲットとしてlambda式またはメソッドの参照として使用できる機能インタフェースを示します.
    T-関数入力のタイプR-関数の結果のタイプ
    public interface Function {
      static  Function identity() {
          return t -> t;
      }
    }

    実際、Java 8では、多くのインタフェースに静的メソッドが追加されています.例えば、Java 8の使用例です.
    public interface Path {
      public static Path get(String first, String... more) {
          return FileSystems.getDefault().getPath(first, more);
      }
    }

    だから、大事なことは、もう一度言いますよ.Java 8から、インタフェースにも静的な方法があります.
    テキストリンク:http://blog.720ui.com/2016/java_se8_01_lambda/
    原文タイトル及び作者:Java 8特性詳細(一)Lambda|梁桂钊のブログ