Java8-Lambda:Lambda語法

又是熱愛學習的一天!!!
在這裏插入圖片描述在這裏插入圖片描述

語法簡介

Java8引入了一種新的操作符 “->”,該操作符叫做 箭頭操作符 或者叫做 Lambda 操作符。箭頭操作符將Lambda表達式分爲了左右兩部分

  • 左側:Lambda 表達式的參數列表。
  • 右側:Lambda 表達式所需執行的功能,也叫Lambda體。

上一篇 初識Lambda文章說道 ,Lambda表達式就是對接口的實現。以前是用匿名內部類去實現的接口,現在是用的Lambda表達式去實現的。

拿上篇文章的 StudentFilter 接口舉例,接口中有個 filter 抽象方法。那麼Lambda表達式的左側就代表的 filter 方法的參數列表。Lambda表達式的右側就是這個方法具體實現的功能

這裏有一個疑問:Lambda 表達式自動的就找到了StudentFilter 接口中的 filter 抽象方法,如果這個接口中有多個抽象方法呢?該怎麼辦?
這裏引出一個新概念:函數式接口

函數式接口

所謂函數式接口就是指接口中只有一個抽象方法的接口,我們稱爲函數式接口。
可以使用註解:@FunctionalInterface 來修飾
如果使用了該註解,那麼就可以檢測這個接口是不是函數式接口,不寫也可以,但是得人工保證函數式接口的規範。而 Lambda 表達式就必須依賴一個函數式接口!

因爲函數式接口的抽象方法可能是多種多樣,比如無參數無返回值、無參數有返回值、有參數無返回值和有參數有返回值等多種情況,那麼就有對應的幾種略微不同的寫法。

語法格式

語法格式一:無參數無返回值

我們在前面說到,Lambda表達式需要函數式接口的支持,那這裏我們是不是需要新創建一個接口,並且增加一個無參數無返回值的抽象方法呢?
其實不用,這種抽象方法其實在Java中已經有一個了,比如:Runnable 接口就是一個函數式接口,接口中的 run 方法就是 無參數無返回值的。

 /**
 * 語法格式一:無參數無返回值
 *     () -> System.out.println("Hello Lambda")
 */
@Test
public void grammar_1(){
    // 原來匿名內部類的寫法
    Runnable r = new Runnable() {
        @Override
        public void run() {
            System.out.println("Hello Inner class");
        }
    };
    r.run();

    System.out.println("************昏 哥 線*************");

    // 現在使用 Lambda 表達式的寫法
    Runnable runnable = () -> System.out.println("Hello Lambda");
    runnable.run();
}

執行結果:

Hello Inner class
************昏 哥 線*************
Hello Lambda

這裏需要提一點: 在 jdk 1.7及以前 如果一個局部類 引用了一個局部變量,那麼這個變量 需要顯示的聲明成 final,在 1.8中就不用顯示的去聲明瞭,編譯器默認給我們加上了,但是這個變量任然是 final 的,是不可以修改的,使用如下所示:

@Test
public void grammar_1(){
    int num = 25; // jdk 1.7及以前,需要顯示的聲明成 final
    // 原來匿名內部類的寫法
    Runnable r = new Runnable() {
        @Override
        public void run() {
            System.out.println("Hello Inner class" + num);
        }
    };
    r.run();

    System.out.println("************昏 哥 線*************");

    // 現在使用 Lambda 表達式的寫法
    Runnable runnable = () -> System.out.println("Hello Lambda" + num);
    runnable.run();
}

語法格式二:有一個參數 無返回值

有一個參數,無返回值的這個接口。 Java裏面也有現成的,他就是:Consumer 接口,它裏面的 accept 抽象方法就符合我們的要求:

/**
 * 語法格式二:有一個參數 無返回值
 *     (x) -> System.out.println(x)
 *
 * 注意:如果只有一個參數,那麼 Lambda表達式左側小括號可以省略不寫,但是建議還是寫上。
 */
@Test
public void grammar_2(){
    Consumer consumer = (x) -> System.out.println(x);
    consumer.accept("你好,Lambda");
}

語法格式三:有兩個及以上參數 有返回值,並且 Lambda體中有多條語句

這種接口Java裏面也有!它就是:Comparator 接口,它裏面的 compare 方法就符合我們的要求:

/**
 * 語法格式三:有兩個及以上參數 有返回值,並且 Lambda體中有多條語句,那麼 Lambda 體需要使用大括號括起來。
 *
 * 注意:如果兩個及以上參數 有返回值,但是 Lambda 體只有一條語句的話,那麼 return 和 大括號可以省略不寫。
 */
@Test
public void grammar_3(){
    Comparator<Integer> comparator = (x, y) -> {
        System.out.println("這是多條語句的 Lambda 體...");
        return Integer.compare(x, y);
    };

    int result = comparator.compare(100, 200);
    System.out.println("返回值爲:"+result);

    System.out.println("************昏 哥 線*************");

    // 這是 Lambda 體只有一條語句的話,那麼 return 和 大括號可以省略不寫 的情況。
    Comparator<Integer> c = (x, y) -> Integer.compare(x, y);
    int result2 = c.compare(200, 500);
    System.out.println("返回值爲:"+result2);
}

回頭看幾個 Lambda 語句,會發現 小括號裏面的參數都是沒有數據類型的,但是編譯運行都沒有問題,這就說明了,Lambda表達式的參數列表的數據類型可以省略不寫,因爲 JVM 編譯器可以通過上下文推斷出數據類型,這個過程就叫做 類型推斷

番外

在上面說到函數式接口中只能有一個抽象方法,但是 Comparator 接口中除去 default 修飾的方法之外,還有兩個,分別是:compare 和 equals。那麼它爲啥還是屬於函數式接口呢?
原因就是 equals 它是 Object的方法,他已經有了默認實現,所以他不算是接口中的抽象方法

從 類的註釋來看,可以總結出以下三點:

  1. 一個函數式接口有且只有一個抽象方法。
  2. 默認方法不是抽象方法,因爲它們已經實現了。
  3. 重寫了超類Object類中任意一個public方法的方法並不算接口中的抽象方法。

所以說 Comparator 接口還是隻有 compare 這一個抽象方法,所以他符合函數式接口的標準

簡單示例

需求:對指定數字進行運算

先創建一個函數式接口

@FunctionalInterface
public interface ICalculation<T> {
    int calc(T x, T y);
}

再寫一個操作方法 operation,具體進行什麼運算現在還不知道,我們對傳入的參數 x 和參數 y 進行運算並返回結果。

public int operation(int x, int y, ICalculation<Integer> iCalculation){
	return iCalculation.calc(x, y);
}

調用 操作方法 operation,傳入實參,使用 Lambda 表達式實現接口中的抽象方法進行運算。下面演示了乘法、加法和減法運算。

@Test
public void lambdaGrammar(){
    int operation = operation(10, 5, (x, y) -> x * y);
    System.out.println("乘法運算結果:"+operation);
    System.out.println("*******昏 哥 線************");

    System.out.println("加法運算結果:"+operation(10, 5, (x, y) -> x + y));
    System.out.println("*******昏 哥 線************");

    System.out.println("減法運算結果:"+operation(10, 5, (x, y) -> x - y));
}

運行結果:

乘法運算結果:50
*******昏 哥 線************
加法運算結果:15
*******昏 哥 線************
減法運算結果:5

總結
Lambda 表達式的語法其實比較簡單,重點是分清它左右側分別是什麼內容,它的左側就對應着函數式接口中抽象方法的參數列表,在它的左側是可以不用寫數據類型的,是因爲有類型推斷機制。如果非要寫上數據類型,那就必須將所有參數都加上數據類型纔可以。
它的右側就是 Lambda 體,就是我們具體實現的內容,如果有多條語句需要使用大括號,只有一條語句可以省略大括號不寫。
在這裏插入圖片描述


技 術 無 他, 唯 有 熟 爾。
知 其 然, 也 知 其 所 以 然。
踏 實 一 些, 不 要 着 急, 你 想 要 的 歲 月 都 會 給 你。


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