Java Lambda

      在〈Java Lambda〉中尚無留言

λ 為希臘的一個字母, 在物理學的公式符號中, 表示波長的意思.

  SAM

SAM的全名為 Single Abstract Method, 單一抽象方法.  指的是一個介面,  只擁有一個單一的抽象方法.  比如下面的介面

interface Runnable{
    void run();
}

每次在執行新的執行緒時, 都需要 new runnable() 產生Runnable的匿名類別, 如下

    new Thread(new Runnable(){
        @Override
        public void run() {
            //要執行的工作任務
        }
    }).start();

像這種只擁有單一抽象方法的介面, 其實多不剩數. 那為什麼要有這麼多無聊的介面呢? 說穿了, 也只是為了多型的目的而以.

上面所說的, 又跟Lambda有什麼關係呢? Lambda是Java8.0新增的功能, 是用來簡化SAM的用法,  不但匿名類別都不用, 連new都省略了.

連匿名類別都不用

Lambda可簡化如下

package ja02;
public class JA02 {
    public static void main(String[] args) {
            new Thread(()->{
            for(int i=0;i<100;i++){
                System.out.printf("%s, %d\n", Thread.currentThread().getName(), i);
                try {Thread.sleep(10);} catch (InterruptedException e) {}
            }
        }).start();
    }
}

上面的寫法, 不用匿名類別, 也不用new出物件, 看似好像把SAM當成了一般函數來看待.  此例子是這樣子沒錯, 可以直接當成函數來看.  而且Java8.0也把SAM稱為 functional interface. 不過Lambda的功能有著意想不到的強, 後續會說明.

驗証真的連類別都沒有

使用Lambda後, 就真的連類別都沒產生嗎? 從下面的程式碼中可以得知, 使用Lambda的片段, 是不可以使用 this.getClass(),  但使用匿名類別的片段, 可以使用this.getClass()取得正確的類別名稱.

package ja02;
public class JA02 {
    public static void main(String[] args) {
        new Thread(()->{
            String threadName=Thread.currentThread().getName();
            for(int i=0;i<100;i++){
                System.out.printf("%s, %s, %d\n", "沒有類別", threadName, i);
                try {Thread.sleep(10);} catch (InterruptedException ex) {}
            }
        }).start();
            
        new Thread(new Runnable(){
            public void run(){
                String threadName=Thread.currentThread().getName();
                for (int i=0;i<100;i++){
                    System.out.printf("%s, %s, %d\n", this.getClass(), threadName, i);
                    try {Thread.sleep(10);} catch (InterruptedException ex) {}
                }
            }
        }).start();
    }
}

結果如下
沒有類別, Thread-0, 0
class ja02.JA02$1, Thread-1, 0
沒有類別, Thread-0, 1
class ja02.JA02$1, Thread-1, 1
沒有類別, Thread-0, 2
class ja02.JA02$1, Thread-1, 2

Lambda表示式

Lambda的表示式可以寫成如下

input -> body

input 及 body 有著多種不同的寫法, 網路上大多寫的霧煞煞. 所以只要記得本章節的說明即可

input只有一個 或 body只有一行 : 可省略() or {}, 當然也可以不省略

另外請注意 Land a1= x ->{}; x可以宣告型態, 也可以不宣告型態. 若有宣告型態, 就一定要加()

public class JavaApp{
    public static void main(String[] args) {
        Land a1=x->System.out.printf("speed : %d\n", x);
        Land a2=(x)->System.out.printf("speed : %d\n", x);
        Land a3=x->{System.out.printf("speed : %d\n", x);};
        Land a4=(x)->{System.out.printf("speed : %d\n", x);};
        Land a5=(int x)->{};
        a1.setSpeed(100);
    }
}
interface Land{
    void setSpeed(int speed);
}

 input 無或多個, body無或多行, 都需() 或 {}

public class JavaApp{
    public static void main(String[] args) {
        Land l=()->{};
        l.setSpeed();
    }
}
interface Land{
    void setSpeed();
}
public class JavaApp{
    public static void main(String[] args) {
        Land l=(x, y)->{
            System.out.println("setup speed");
            return x+y;
        };
        int speed=l.setSpeed(10,20);
    }
}
interface Land{
    int setSpeed(int x, int y);
}

body只有一行返回值

這種最機車, 有二種寫法, body需使用 {return xxx;}.  或者是無{}也沒return, 直接寫返回值即可.

public class JavaApplication56 {
    public static void main(String[] args) {
        Land a1=()->{return 10;}; //第一種
        Land a2=()-> 10; //第二種
        System.out.printf("speed : %d\n",l.setSpeed());
    }
}
interface Land{
    int setSpeed();
}

行為參數化

Todo

介面函數變成方法參數

這是一個非常強大的功能, 請看如下程式碼. 先定義一個 MathOperator的介面, 裏面只有一個operate的抽象方法.
再使用Lambda產生addOperator, subOperator, multiPoerator, divOperator四個介面函數(其實也可以看成是物件啦), 再傳入calculate的方法, 如此就可得到不同的計算結果.

不過也不是說只有Lambda才可以作到此功能啦. 傳統的方式也可以. 如下藍色的部份, 就是使用匿名類別並傳入powOperator這個物件就可以達成, 只是寫的比較長一點而以.

public class JavaApp{
    public static void main(String[] args) {
        MathOperator addOperator=(int x, int y)->x+y;
        MathOperator subOperator=(x, y)->x-y;
        MathOperator multiOperator=(x, y)->{return x*y;};
        MathOperator divOperator=(x, y)->x/y;
        int x=100, y=10;
        System.out.printf("相加 : %d\n",calculate(x, y, addOperator));
        System.out.printf("相減 : %d\n",calculate(x, y, subOperator));
        System.out.printf("相乘 : %d\n",calculate(x, y, multiOperator));
        System.out.printf("相除 : %d\n",calculate(x, y, divOperator));
        MathOperator powOperator=new MathOperator(){
            @Override
            public int operate(int x, int y) {
                return (int)(Math.pow(x, y));
            }
        };
        System.out.printf("冥次方 : %d\n",calculate(2, 10, powOperator));
    }
    private static int calculate(int a, int b, MathOperator operator){
       return operator.operate(a, b);
    }
}
interface MathOperator{
    int operate(int x, int y);
}

發佈留言

發佈留言必須填寫的電子郵件地址不會公開。 必填欄位標示為 *