從Java5基礎開始初識Lambda表達式——走進Java Lambda(一)

從Java5開始初識Lambda表達式

        Lambda表示式是Java8的特性,對於如何安裝Java8,裝哪個版本的什麼IDE,可以支持Java8語法,這裏就恕不介紹了。請你確認安裝了環境再往下看,真的,謝謝你。

        我們知道在Java裏面,所有參數都有一個類型。那麼Lambda表達式裏面,參數是什麼呢,上一篇說了Lambda是函數編程,所以Lambda傳遞的是“函數”,函數是Java的新類型嗎?不是,Java裏面函數不妨叫做函數接口(functional interface)。他滿足這樣的條件:首先他的類型是interface,而且有且僅有一個抽象方法,然後有N(N>=0)default方法和static方法。對,是方法不是抽象方法哦。Java1-7接口沒有方法,Java8的函數接口可以有default方法和靜態方法,改動很大。接口放靜態方法做啥呢,估計爲了龜飯吧。

我們先不扯這麼遠,還是從熟悉的說起吧。看看下面Map類,假設在Java7中發生了這樣的變化

          Map<String,String> params = new HashMap<String, String>(); //Java7以前的風格
          Map<String,String> params = new HashMap<>(); //Java7的風格

        Java7裏面初始化一個Map對象時,已經可以不指定類型了[哥就那麼一說,要是你這樣編譯通不過,不要問我爲什麼],編譯器可以自動識別,當然你非要指定那也是極好的(反正IDE有代碼補全功能是伐?),這裏我要說的是Java7的編譯器更加智能了。那麼Java8裏面編譯器可以更智能了,連方法都可以省略。一個對象方法省略了,會調用那個方法呢,亂調用,這樣真的合適嗎?當然不合適啦,所以人家編譯器規定你,這個對象裏面只可以有一個讓他能夠一下子就找到的方法,意即函數接口裏面有且僅有一個抽象方法。那麼我們先從下面的例子入手吧。

@Test
public void preTest() {
    Predicate<Integer> bigerThan6 = x ->  x > 6;
    System.out.println(bigerThan6.test(7));
    System.out.println(bigerThan6.negate().test(7));
}

1. Predicate<Integer> bigerThan6 = x -> x > 6;//聲明一個Lambda表達式
2. System.out.println(bigerThan6.test(7)); //結果是 true
3. System.out.println(bigerThan6.negate().test(7));// 結果是false

我們先看看 處,這裏若果是不用Lambda風格,實現方式我們得這麼寫:

Predicate<Integer> bigerThan6  =new Predicate<Integer>() {
                @Overridepublic 
                 boolean test(Integer t) {
                     return  t > 6 ;
                }
};

        而現在只需要寫帶陰影的這段代碼,其餘代碼在編譯器編譯的時候,自動幫你補全了。上面我們用到了Predicate這個類,Predicate是什麼玩意呢。他是JDK裏面java.util.function包下的一個接口。我們看看他的源碼


    我們看到這個類完全滿足前面對“函數接口”的要求(一個抽象方法),也就是說這個接口就是個“函數接口”。我們也發現了 2 3兩處我們最後都只調用了一個方法test()。那麼處多調用了negate()方法,是什麼意思呢,我們看negate()方法在源碼裏面是這麼寫的:

default Predicate<T> negate() {
    return (t) -> !test(t);
}

    原來就是取反的意思。代碼意思是說,當調用test方法是進行取反操作,源碼裏這段寫法也許有點陌生,其實他相當於非Lambda風格的以下代碼:

default Predicate<T>negate(final Predicate<T> instance) {
    return new Predicate<Integer>() {
        @Override
        public boolean test(Integer t) {
            return !instance.test(t);
        }
    };
}

看到以前風格的代碼不顯得頭大麼。Java8只要一行代碼就取代了之前那麼多代碼,感覺世界美好起來了。看到了麼,這個就算是一種所謂的“無副作用”方法修改,看是修改了方法,其實不影響原方法使用。

講完了“取反”操作,有沒有“或”操作呢,細心的朋友或許看到了,Predicate源碼中有一個or方法。怎麼用,下面舉例例子:

Predicate<Integer> bigerThan6 = x -> x > 6;//聲明一個Lambda表達式
Predicate<Integer> lessThan3 = x -> x < 3; //聲明另一個Lambda表達式
System.out.println(bigerThan6.or(lessThan3).test(1));//true 因爲1<3

這裏我就不貼上關於or(Predicate<? super T> other)方法的非Lambda實現代碼了吧,相信聰明的你,可以根據以上例子自己推敲出來。

    Predicate的抽象方法test是隻接受一個參數的傳遞。要是一個方法要傳遞多個參數呢?接下來就看看另外一個類BinaryOperator<T>,他有一個apply方法,是接受兩個參數的。這個方法要求傳入的兩個參數,參數類型是一樣的,而且返回值也是參數類型。假如我們要求兩個數(x,y)之差。我們可以這樣寫

/**
 * 測試BinaryOperator方法
 */
@Test
public void binaryOperator() {
    BinaryOperator<Integer> biopt = (x,y) -> x - y;//注意這裏的雙參數,是加了括號的。僅一個參數時可以省略括號,其他參數個數不能省,包括空參數
    System.out.println(biopt.apply(2, 4));
}
上面代碼等價於
@Test
public void binaryOperator() {
    BinaryOperator<Integer> biopt = new BinaryOperator<Integer>() {
        @Override
        public Integer apply(Integer x, Integer y) {
            return x-y;
        }
    };
    System.out.println(biopt.apply(2, 4));
}
若果我們需要結果是絕對值,那麼可以在加減運算之前判斷大小關係。可以寫成下面這樣

@Test
public void minAbs() {
    BinaryOperator<Integer> biopt = (x,y)->{//注意這裏的方法塊括號,僅一條語句時可以省略花括號
            if(x<y){
                return y-x;
            } 
            return x-y;//注意,當傳入方法塊的時候,“return” 不能省略
        };
    System.out.println(biopt.apply(2, 4));
}

相當於代碼

@Test
public void minAbs() {
    BinaryOperator<Integer> biopt = new BinaryOperator<Integer>() {
        @Override
        public Integer apply(Integer x, Integer y) {
            if(x<y){
                return y-x;
            }
            return x-y;
        }
    };
    System.out.println(biopt.apply(2, 4));
}
到目前爲止,我們對Lambda的語法習慣應該有一個瞭解了。JDKjava.util.function包下還有很多函數接口類型的類,這裏就先不一一介紹了。這裏只是做一個初步瞭解

那麼問題來了:

① Lambda表達式聲明時要不要寫方法名,爲什麼?

② Lambda表達使用的函數接口能否有方法,若能,這些方法有什麼限制嗎?

③ Lambda表達式使用的接口一般叫做“函數接口”,說明Lambda用是什麼編程方式?(函數編程)

④ Runnable接口可否用於Lambda表達式。

⑤ 嘗試,在上面代碼 處用下面代碼代替能否編譯和運行,結果會是什麼樣。

Predicate<Integer> bigerThan6 = x -> {
            System.out.println("you are welcome "+x);
            return x > 6;
        };


發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章