1. 程式人生 > 其它 >Java8InAction-行為引數化與Lambda

Java8InAction-行為引數化與Lambda

1、摘要

  用更少的程式碼幹更多的事,一直是程式設計師的追求。

  但是很多時候,需求的變化,很容易讓我們寫出高度冗餘的程式碼。

  很多函式可能就是幾句核心程式碼不一樣,複製貼上稍微改改就行。

  行為引數化,就是把行為封裝起來,然後作為引數傳遞。

  策略模式就是一種行為引數化的實現,將行為封裝在不同的類中,然後通過傳遞類來傳遞行為。

  但是,為了封裝行為而寫一個類,有點大材小用,寫了很多不必要的程式碼。

  我們有沒有一種能夠直接傳遞行為的方法呢?

  有,那就是Lambda表示式。它可以封裝一個行為並可以進行傳遞。

  Lambda為什麼這麼神奇呢?

  實際上Lambda只能稱得上是一個Java的語法糖,

  它只是將我們建立Java類,生成Java物件的操作交給了JVM來實現,簡化了我們的工作,

  但是並沒有新增新的特性,自己封裝類做不到的它也做不到。

  在JVM執行到lambda表示式時,它會根據上下文中的型別資訊,將表示式繫結到一個介面(函式式介面),

  然後,再使用動態生成位元組碼的方式,建立一個實現了該介面的類來封裝表示式的功能,

  最後,再建立該類的的一個物件。

2、行為引數化

  阿拉丁神燈最近很煩躁,因為對許願者的每一個願望,神燈都要念一段長長的咒語。

  先是要念咒語來激發神力,然後才能使用神力來實現願望,最後還要念咒語收回神力。

  可是,隨著神力越來越強大,神燈需要念的咒語也越來越長了。

  經常會出現唸咒兩小時,實現願望兩分鐘的情況。

  許願者的每次都要等很久,差評愈來愈多了。

  於是神燈去找了智慧之神。

public class Ald {
    void wish1(){
        System.out.println("power activated!");
        System.out.println("a");
        System.out.println("power deactivated!");
    }
    void wish2(){
        System.out.println("power activated!");
        System.out.println(
"b"); System.out.println("power deactivated!"); } void wish3(){ System.out.println("power activated!"); System.out.println("c"); System.out.println("power deactivated!"); } }

  智慧之神看了神燈實現願望後,說,你也太笨了吧,就不會發明一個自動咒語機嘛。

  只用傳入願望就行了,咒語機自動念咒語。

public class Ald {
    void wish1(String a){
        System.out.println("power activated!");
        System.out.println(a);
        System.out.println("power deactivated!");
    }
}

  使用了自動咒語機一段時間之後,神燈還是不太滿意。

  機器一次只能傳入一個咒語,但是,好多願望要好幾個咒語才能實現。

  因此,它又去找了智慧之神。

  智慧之神不想跟他說話,並扔給他又一個咒語機。

interface wish{
    public void handleWish();
}

class wish1 implements wish{
    @Override
    public void handleWish() {
        System.out.println("哇啦哇啦");
        System.out.println("wish2!");
        System.out.println("巴卡巴卡");
    }
}

class wish2 implements wish{
    @Override
    public void handleWish() {
        System.out.println("烏拉烏拉");
        System.out.println("wish2!");
        System.out.println("巴卡巴卡");
    }
}

public class Ald {
    void wish1(wish a){
        System.out.println("power activated!");
        a.handleWish();
        System.out.println("power deactivated!");
    }
}

  。。。編不下去了。。。。還是看程式碼吧。。。

  使用策略模式雖然更加的清晰了,但是,卻不免要建立一些策略類,

  對於不會反覆使用的策略,還要建立一個類,是不大划算的。

interface wish{
    public void handleWish();
}

public class Ald {
    void wish(wish a){
        System.out.println("power activated!");
        a.handleWish();
        System.out.println("power deactivated!");
    }

    public static void main(String[] args) {
        Ald ald=new Ald();
        ald.wish(new wish() {
            @Override
            public void handleWish() {
                System.out.println("烏拉烏拉");
                System.out.println("wish2!");
                System.out.println("巴卡巴卡");
            }
        });
    }
}

  使用匿名類可以簡化建立類的程式碼。

interface wish{
    public void handleWish();
}

public class Ald {
    void wish(wish a){
        System.out.println("power activated!");
        a.handleWish();
        System.out.println("power deactivated!");
    }

    public static void main(String[] args) {
        Ald ald=new Ald();
        ald.wish(() -> {
            System.out.println("烏拉烏拉");
            System.out.println("wish2!");
            System.out.println("巴卡巴卡");
        });
    }
}

  使用匿名錶達式,則更進了一步,連方法名這些都簡化了。

3、Lambda表示式

  匿名錶達式結構:

    (param)->expression  或

    (param)->{ sentences; }

  函式式介面:

    即只有一個抽象方法的介面(可以有多個預設方法)。

    至於只有一個抽象方法,應該是為了便於繫結吧。畢竟匿名錶達式只能以引數和返回值來區分。

    因此一個匿名錶達式可以繫結到多個函式式介面上,只要引數、返回值匹配。

  java.util.function中定義了很多函式式介面,我們也能建立自己的函式式介面。

  方法引用:

    根據已有的方法來建立Lambda表示式。

    這是在Lambda表示式中呼叫特定方法的一種便捷寫法。

    方法引用說明了在建立的Lambda中執行哪個方法。

    主要有三類:

      1、指向靜態方法的方法引用

        如 Integer::parseInt

        指向構造器 ClassName::New(parameter)

      2、指向類方法的方法引用

        如 String::length

      3、指向例項方法的方法引用

        假設 a是一個物件,並且a是lambda表示式的一個引數,則可以使用方法引用來指向a的例項方法

        (A a)->a.method; 或 (A a, B b)->a.mothod(b);   可改寫為:

        a::method

@FunctionalInterface
interface Wish {
    void handleWish();

    static void defaultHandleWish() {
        System.out.println("defaultHandleWish!");
    }

    default public void defaultHandleWishNonStatic() {
        System.out.println("defaultHandleWishNonStatic");
    }
}


class Wish1 implements Wish{
    Wish1(){
        System.out.println("New!");
    };
    public static void handleWish1() {
        System.out.println("handleWish1");
    }
    @Override
    public void handleWish() {
        System.out.println("handleWish2");
    }
}

public class Ald {
    void wish(Wish a){
        System.out.println("power activated!");
        a.handleWish();
        System.out.println("power deactivated!");
    }

    public static void main(String[] args) {
        Ald ald=new Ald();
        Wish1 wish1=new Wish1();

        ald.wish(Wish1::handleWish1);   //指向靜態方法,此時,a.handleWish();執行的是Wish1::handleWish1方法
        ald.wish(Wish1::new);           //指向構造器,此時,a.handleWish();執行的是Wish1的構造器方法
        ald.wish(wish1::handleWish);    //指向例項方法,此時,a.handleWish();執行的是wish1::handleWish方法
        ald.wish(()-> System.out.println("handleWish3"));   //lambda,此時,a.handleWish();執行的是System.out.println("handleWish3")語句
        ald.wish(Wish::defaultHandleWish);                  //同樣Lambda中也能執行介面的static方法
        ald.wish(wish1::defaultHandleWishNonStatic);        //執行介面中的預設方法
    }
}

New!
power activated!
handleWish1
power deactivated!
power activated!
New!
power deactivated!
power activated!
handleWish2
power deactivated!
power activated!
handleWish3
power deactivated!
power activated!
defaultHandleWish!
power deactivated!
power activated!
defaultHandleWishNonStatic
power deactivated!