jdk 8における関数式lambdaとそれに関連する新しい特性

10034 ワード

Lambda式の概念
->表現を使用する私たちをlambda式と呼び、指定したインタフェースを実現し、インタフェースオブジェクトの書き方を返します.
public class ThreadDemo {

    public static void main(String[] args) {
        Object target = new Runnable() {

            @Override
            public void run() {
                System.out.println("ok");
            }
        };
        new Thread((Runnable) target).start();

        // jdk8 lambda
        Object target2 = (Runnable)() -> System.out.println("ok");
        Runnable target3 = () -> System.out.println("ok");
        System.out.println(target2 == target3); // false
        
        new Thread((Runnable) target2).start();
    }

}


Lambda式を使用するインタフェースの要件は、インタフェースにインタフェースメソッドが1つしかないことです.これも私たちがインタフェースを書くときにできるだけインタフェースを書かないように導き、できるだけ単一責任制を守ることです.jdk 8には、@FunctionalInterfaceタグを使用して、@overrideと同様にコンパイラの検証として機能する関数インタフェースという新しい名前が導入されています.
デフォルトメソッド、またはデフォルト実装メソッドと呼ばれ、lambda式でインタフェースインスタンスを得ることができ、このデフォルトメソッドを使用して、デフォルトメソッドをクラス内のメソッドとして理解することができます.
@FunctionalInterface
interface Interface1 {
    int doubleNum(int i);

    default int add(int x, int y) {
        return x + y;
    }

    static int sub(int x, int y) {
        return x - y;
    }
}


    public static void main(String[] args) {
        Interface1 i1 = (i) -> i * 2;

        Interface1.sub(10, 3);
        System.out.println(i1.add(3, 7));
        System.out.println(i1.doubleNum(20));
}


jdk 8で提供される関数インタフェース
まず、数字のフォーマットを実現し、お金のフォーマットを「#,###」にフォーマットします.私たちは次のコードを使用して実現します.
import java.text.DecimalFormat;

/**
 * @author    
 * @version 1.0.0
 * @date 2018/7/29
 */
interface IMoneyFormate {
    String formate(int money);
}

class MyMoney1 {
    private final int money;
    public MyMoney1(int money) {
        this.money = money;
    }
    public void printMoney(IMoneyFormate moneyFormat) {
        System.out.println("    :" + moneyFormat.formate(this.money));
    }
}

public class MoneyDemoOld {
    public static void main(String[] args) {
        MyMoney1 me = new MyMoney1(99999999);
        me.printMoney( i -> new DecimalFormat("#,###")
                .format(i));
    }
}

コードを見ると、このインタフェースIMoneyFormateはあまり必要ないことがわかります.実際には、このインタフェースの役割はパラメータタイプの戻り値タイプを教えてくれるので、jdk 8の新しい特性を同時に使用することができます.Functionを使用して、メソッドがインタフェースタイプを受け入れていることを示します.パラメータと戻り値タイプがintgerとstringであることを指定し、applyメソッドを呼び出します.最後に、新しいプロパティの関数インタフェースチェーン操作を同時に使用しました.コードは次のとおりです.
class MyMoney {
    private final int money;
    public MyMoney(int money) {
        this.money = money;
    }
    public void printMoney(Function moneyFormat) {
        System.out.println("    :" + moneyFormat.apply(this.money));
    }
}

public class MoneyDemo {
    public static void main(String[] args) {
        MyMoney me = new MyMoney(99999999);
        Function moneyFormat = i -> new DecimalFormat("#,###")
                .format(i);
        //         
        me.printMoney(moneyFormat.andThen(s -> "    " + s));
    }
}


新しいプロパティデフォルトインタフェースメソッドデフォルトメソッドはクラス内のメソッドとして使用できますデフォルトだけでなく静的メソッドもコードを見ることができます
@FunctionalInterface
interface Interface1 {
    int doubleNum(int i);

    default int add(int x, int y) {
        return x + y;
    }

    static int sub(int x, int y) {
        return x - y;
    }
}
public strictfp class LambdaDemo1 {

    public static void main(String[] args) {
        Interface1 i1 = (i) -> i * 2;

        Interface1.sub(10, 3);  //7
        System.out.println(i1.add(3, 7));   //10
        System.out.println(i1.doubleNum(20));  //40

        //         
        Interface1 i2 = i -> i * 2;

        Interface1 i3 = (int i) -> i * 2;

        Interface1 i4 = (int i) -> {
            System.out.println("-----");
            return i * 2;
        };

    }

}

アサーション関数と消費者関数
public class FunctionDemo {

    
    public static void main(String[] args) {
        //       
        IntPredicate predicate = i -> i > 0;
        System.out.println(predicate.test(-9));
        
        //
        // IntConsumer

        //       
        Consumer consumer = s -> System.out.println(s);
        consumer.accept("     ");
    }

}

メソッド参照
Consumer consumer = s -> System.out.println(s);

あなたの方法のパラメータが戻り値のタイプと同じように、s用を省略することができます.
Consumer consumer=System.out::println

メソッド参照の種類1、静的メソッドの参照使用メソッドクラス名にメソッド名を付けるクラス名::メソッド名2、非静的メソッド非静的メソッドの例::メソッド名非静的メソッドは、jdkがメソッドごとに値を渡すと印刷されたときの最初のパラメータがthis
public void test(String s){
    
}

コンパイルすると
//Demo   
public void test(Demo this,String s){
    
}

したがって,非静的メソッドでクラス名に方法名を付ける方法は
BigFunction =  ::new

3、構造関数の方法引用はパラメータを含まない
function     =   ::new

パラメータを含む
function     =  ::new
package lambda;

import java.util.ArrayList;
import java.util.List;
import java.util.function.Consumer;
import java.util.function.IntUnaryOperator;

class Dog {
    private String name = "   ";

    /**
     *   10   
     */
    private int food = 10;

    public Dog() {

    }

    /**
     *         
     * 
     * @param name
     */
    public Dog(String name) {
        this.name = name;
    }

    /**
     *   ,    
     * 
     * @param dog
     */
    public static void bark(Dog dog) {
        System.out.println(dog + "  ");
    }

    /**
     *     JDK
     * 
     *                 ,    this,      ;
     * 
     * @param num
     * @return       
     */
    public int eat(int num) {
        System.out.println("  " + num + "   ");
        this.food -= num;
        return this.food;
    }

    @Override
    public String toString() {
        return this.name;
    }
}

public class MethodRefrenceDemo {

    public static void main(String[] args) {
        Dog dog = new Dog();
        dog.eat(3);

        //     
        Consumer consumer = System.out::println;
        consumer.accept("     ");

        //          
        Consumer consumer2 = Dog::bark;
        consumer2.accept(dog);

        //      ,           
        // Function function = dog::eat;
        // UnaryOperator function = dog::eat;
        IntUnaryOperator function = dog::eat;
        
        // dog  ,          ,  java      
        dog = null;
        System.out.println("   " + function.applyAsInt(2) + " ");
        //
        // //          
        // BiFunction eatFunction = Dog::eat;
        // System.out.println("   " + eatFunction.apply(dog, 2) + " ");
        //
        // //          
        // Supplier supplier = Dog::new;
        // System.out.println("      :" + supplier.get());
        //
        // //              
        // Function function2 = Dog::new;
        // System.out.println("      :" + function2.apply("  "));

    }

    private static void test(List list) {
        list = null;
    }
}


Lambda式のタイプ推定
package lambda;

@FunctionalInterface
interface IMath {
    int add(int x, int y);
}

@FunctionalInterface
interface IMath2 {
    int sub(int x, int y);
}


public class TypeDemo {

    public static void main(String[] args) {
        //       
        IMath lambda = (x, y) -> x + y;

        //    
        IMath[] lambdas = { (x, y) -> x + y };

        //   
        Object lambda2 = (IMath) (x, y) -> x + y;
        
        //       
        IMath createLambda = createLambda();
        
        TypeDemo demo = new TypeDemo();
        //         ,           
        demo.test( (IMath2)(x, y) -> x + y);
    }
    
    public void test(IMath math) {
        
    }
    
    public void test(IMath2 math) {
        
    }
    
    public static IMath createLambda() {
        return  (x, y) -> x + y;
    }

}


Lambda式の変数参照
エピソードjdk 8の前に内部クラスが外部クラスを引用するこのクラスはfinalタイプでなければならない.jdk 8ではこのfinalは省略できるが、依然としてfinalである.
import java.util.ArrayList;
import java.util.List;
import java.util.function.Consumer;

/**
 *     
 */
public class VarDemo {

    public static void main(String[] args) {
        List list = new ArrayList<>();
        Consumer consumer = s -> System.out.println(s + list);
        consumer.accept("1211");
    }

}

カスケード式とコリー化カスケード式はx->y->x+yである.この形で完全に意味が書けるようになった
Function>=x->y->x+y;

つまりyは1つの関数でxの戻り関数として、yはまたx+yの戻り関数で、いわゆるコリー化は複数のパラメータが1つのパラメータになってコードを見ることです
import java.util.function.Function;

/**
 *           
 *    :                     
 *       :     
 *     :         
 */
public class CurryDemo {

    public static void main(String[] args) {
        //    x+y      
        Function> fun = x -> y -> x
                + y;
        System.out.println(fun.apply(2).apply(3));

        Function>> fun2 = x -> y -> z -> x
                + y + z;
        System.out.println(fun2.apply(2).apply(3).apply(4));

        int[] nums = { 2, 3, 4 };
        Function f = fun2;
        
        for (int i = 0; i < nums.length; i++) {
            if (f instanceof Function) {
                Object obj = f.apply(nums[i]);
                if (obj instanceof Function) {
                    f = (Function) obj;
                } else {
                    System.out.println("    :   " + obj);
                }
            }
        }
    }
}