1. 程式人生 > >Java裏的lambda表達式

Java裏的lambda表達式

賦值 繼續 turn 編譯器 括號 必須 推導 lan https

在上一篇文章《Java裏的函數式接口》介紹了關於函數式接口的內容,那麽本文基於函數式接口來繼續學習lambda表達式。

  • 語法結構
Runnable runnable = () -> System.out.println("Runnable Instance");

這種使用箭頭符號->分開參數列表和方法體的語法就是lambda表達式。在Java 裏沒有和lambda 表達式對應的類定義或者代碼庫,lambda表達式總是在定義後賦值給某個函數式接口類型變量。

一個 lambda表達式的參數列表聲明和方法實現必須和所賦值的函數式接口函數中的抽象方法匹配。關於lambda表達式和函數式接口之間的關系還有以下註意點:

  1. 參數列表的括號必不可少,即使沒有參數聲明。
  2. 參數列表的參數聲明順序要和函數式接口的抽象方法一致,而且可以省略參數的類型聲明。
  3. 方法體若只有一行代碼,則可以省略方法體聲明的中括號,如果方法體有返回值,則也可以省略return關鍵字。若加上了中括號,那麽return關鍵字必須補上。
  4. 方法體若不止一行代碼,中括號不可以省略,返回值的return關鍵字也不可以省略。
  • 使用變量

在lambda表達式裏可以使用上下文中的變量,但是和匿名類中使用上下文變量一樣的限制,要求變量必須是final的。

然而在Java8裏,也可以不明確的加上final,只需要該變量是一種“形式final”即可。例如以下代碼會通過編譯並正常運行:

        String message = "Message";
        Runnable runnable = () -> System.out.println(message);
        new Thread(runnable).start();

message變量並沒有加上關鍵字final,但是很明顯它被初始化之後沒有對它進行任何操作,所以“顯然”它肯定是“不可變”的,所以可以在lambda 表達式裏使用。但是以下代碼就不能通過編譯:

        String message = "Message";
        message = "Message2";
        Runnable runnable 
= () -> System.out.println(message); new Thread(runnable).start();

在message初始化之後,又進行了一次賦值操作,明顯不符合一個final變量只能賦值一次的約束,所以lambda表達式裏不能使用。

關於在Java8裏引入的這種新特性,到底是什麽實現的呢?我們可以編譯代碼之後查看class文件,就會發現上述代碼變成了以下樣子:

final String message = "Message";
        Runnable runnable = () -> {
            System.out.println(message);
        };
        (new Thread(runnable)).start();

編譯器自動給message加上了final關鍵字。

  • 總結

lambda表達式不單獨存在和使用,它總是從上下文中推導參數類型和自己的類型,可以把lambda表達式賦值給符合條件的函數式接口類型變量,也可以把它傳遞給接受符合條件的函數式接口類型的方法裏。通過lambda表達式,我們可以真的做到將代碼塊作為變量一樣使用。

Java裏的lambda表達式