読書ノート——『Java 8実戦』シリーズのLambda表現式(二)


転入先http://www.wxueyuan.com/blog/articles/2017/10/16/1508115706213.html
前回のブログではLambda式の基本概念と文法を紹介しました.このブログでは、Lambda式に関する知識を引き続き共有します.
関数インタフェースは、関数記述子とも呼ばれる抽象メソッドのみを定義します.異なるLambda式を適用するために、Javaのライブラリデザイナーたちは、以前に接触したComparable、Runnable、Callableなどの一般的な関数インタフェースを提供しています.Java 8に基づいて、いくつかの新しい関数インタフェースが追加されました.次に、それらを理解してみましょう.
java.util.function.Predicate
Predicateインタフェースはtestという抽象的な方法を定義し、汎用Tのオブジェクトを受け入れ、Boolean値を返します.このシリーズの読書ノートを見たことがある学生たちはよく知っていると思いますか?そう、動作パラメータ化ブログで自分で作成した関数インタフェースと同じです.入力オブジェクトを使用してブール値を返す式が必要な場合は、そのまま使用しましょう.
    @FunctionalInterface
    public interface Predicate<T>{
        boolean test(T t);
    }

    public static  List filter(List list, Predicate p) {
        List results = new ArrayList<>();
        for(T s: list){
            if(p.test(s)){
                results.add(s);
            }
        }
        return results;
    }
    Predicate nonEmptyStringPredicate = (String s) -> !s.isEmpty();

    List nonEmpty = filter(listOfStrings, nonEmptyStringPredicate);

java.util.function.Consumer
Consumerはaccept抽象メソッドを定義した.汎用型オブジェクトTを受け入れ、値は返されません.Tタイプのオブジェクトにアクセスし、いくつかの操作を実行する必要がある場合は、このインタフェースを使用します.
    @FunctionalInterface
    public interface Consumer<T>{
        void accept(T t);
    }

    public static  void forEach(List list, Consumer c){
        for(T t:list){
            c.accept(t);
        }
    }

    forEach(Arrays.asList(1,2,3,4,5), (Integer i)-> System.out.println(i));

java.util.function.Function
    @FunctionalInterface
    public interface Function<T,R>{
        R apply(T t);
    }

    public static  List map(List list, Function f){
        List result = new ArrayList();
        for(T t: list){
            result.add(f.apply(t));
        }
    }

    List list = map(Arrays.asList("hello","world","Jesmin"),(String s) -> s.length());

次に、一般的なLambdaの例と使用可能な関数インタフェースをまとめます.
使用例
Lambdaの例
対応する関数インタフェース
ブール式
(List list) -> list.isEmpty()
Predicate>
オブジェクトの作成
( ) -> new String()
Supplier
一つの対象を消費する
( String s ) -> { System.out.println(s);}
Consumer
オブジェクトからの属性の抽出
( Student s ) -> s.getHeight()
FunctionまたはToIntFunction
2つの値を結合
( int a, int b ) -> a*b
IntBinaryOperator
2つのオブジェクトの比較
( Student s1, Student s2 ) -> s1.getHeight().compareTo(s2.getHeight())
Comparator
これまで紹介したLambda式はすべて,学生インスタンスの身長属性を用いたような主体のパラメータにのみ用いられてきた.
    List result = filter(students, (Student s) -> s.getHeight()>=180));

しかし、実際にはLambda式では、自由変数(パラメータとして使用することはできません.本体で外層の役割ドメインで定義された変数を使用することはできません)を使用することもできます.
    int num = 5;
    Runnable r = () -> System.out.println(num);

Lambda式は、インスタンス変数と静的変数を本体で使用することもできます.ただし、ローカル変数はfinalと明示的に宣言するか、実際にfinalとして宣言する必要があります.言い換えれば、Lambda式本体で使用されたローカル変数は、再付与できません.
エラーの例:
    int num = 5;
    Runnable r = () -> System.out.println(num);
    //       ,   Lambda            num      
    num = 3;