Java8新特性系列-Lambda

小愛部落格發表於2022-03-02

Lambda Expressions in Java 8

Lambda 表示式是 Java 8 最流行的特性。它們將函數語言程式設計概念引入 Java,這是一種完全物件導向的指令式程式設計語言。 函數語言程式設計語言的工作原理超出了本文的範圍,但我們將提取一個特性,該特性對於使用 OOP 的我們來說是顯而易見的。

在這篇文章中,我們將瞭解 lambda 表示式到底是什麼以及它們如何融入整個 Java 生態系統。 我們還將檢視不使用 lambda 表示式的示例程式碼,然後重構此程式碼以使用 lambda。

理解一個Lambda表示式

Lambda 表示式是我們可以傳遞執行的程式碼塊。 將程式碼塊傳遞給函式是我們作為 Java 程式設計師不習慣的事情。 我們所有的行為定義程式碼都封裝在方法體中,並通過物件引用執行,就像使用以下程式碼一樣:

public class LambdaDemo {
    public void printSomething(String something) {
        System.out.println(something);
    }

    public static void main(String[] args) {
        LambdaDemo demo = new LambdaDemo();
        String something = "I am learning Lambda";
        demo.printSomething(something);
    }
}

這是對呼叫者隱藏方法實現的經典 OOP 風格。 呼叫者只需將一個變數傳遞給該方法,然後該方法對變數的值執行一些操作並返回另一個值或產生副作用,就像在我們的例子中一樣。

我們現在將看到一個等效的實現,它使用行為傳遞而不是變數傳遞。 為了實現這一點,我們必須建立一個函式式介面來定義抽象行為而不是方法。 功能介面是隻有一個方法的介面:

public class LambdaDemo {
    interface Printer {
        void print(String val);
    }

    public void printSomething(String something, Printer printer) {
        printer.print(something);
    }
}

在上面的實現中,Printer 介面負責所有的列印。 printSomething 方法不再定義行為,而是執行由 Printer 定義的行為:

public static void main(String[] args) {
    LambdaDemo demo = new LambdaDemo();
    String something = "I am using a Functional interface";
    Printer printer = new Printer() {
        @Override
        public void print(String val) {
            System.out.println(val);
        }
    };
    demo.printSomething(something, printer);
}

你們中的細心的人可能已經注意到我們在這裡沒有做任何新的事情。 這是真的,因為我們還沒有應用 lambda 表示式。 我們簡單地建立了 Printer 介面的具體實現並將其傳遞給 printSomething 方法。

上面的演示旨在將我們帶到在 Java 中引入 Lambda 表示式的關鍵目標:Lambda 表示式主要用於定義功能介面的內聯實現。

在我們使用 lambda 表示式重構上面的例子之前,讓我們學習必要的語法:

(param1,param2,param3...,paramN) - > {//block of code;}

一個 lambda 構成一個用括號括起來的逗號分隔的形式引數列表,就像我們在方法宣告中定義的那樣,後跟一個指向要執行的程式碼的箭頭標記。 現在讓我們重構上面的程式碼以使用 lambda:

public static void main(String[] args) {
    LambdaDemo demo = new LambdaDemo();
    String something = "I am learning Lambda";
    /**/
    Printer printer = (String toPrint)->{System.out.println(toPrint);};
    /**/
    demo.printSomething(something, printer);
}

非常緊湊和美觀。 由於函式式介面只宣告瞭一個方法,因此在 lambda 的第一部分中傳遞的引數會自動對映到方法的引數列表中,並且箭頭右側的程式碼被視為方法的具體實現

為什麼要使用Lambda表示式

與上一節中的演示一樣,lambda 表示式使我們能夠擁有更緊湊的程式碼,更易於閱讀和遵循。 在效能和多核處理方面還有其他好處,但只有在瞭解 Streams API 後才能理解,因此超出了本文的範圍。

比較使用和不使用 lambda 的主要方法實現肯定向我們展示了 lambda 表示式在縮短程式碼方面的強大功能:

public static void main(String[] args) {
    LambdaDemo demo = new LambdaDemo();
    String something = "I am learning Lambda";
    /**/
    Printer printer = (String toPrint)->{System.out.println(toPrint);};
    /**/
    demo.printSomething(something, printer);
}

我們可以讓我們的程式碼比這更簡潔。 碰巧的是,即使沒有在箭頭左側指定引數的型別,編譯器也會從介面方法的形式引數中推斷出它的型別:

Printer printer = (toPrint)->{System.out.println(toPrint);};

我們仍然可以做得更好。 lambda 的另一個特點是:如果只有一個引數,我們可以完全去掉括號。 同樣,如果箭頭右邊只有一個語句,我們也可以去掉大括號:

Printer printer = toPrint -> System.out.println(toPrint);

現在我們的程式碼真的開始看起來很可愛了。 我們才剛剛開始。 如果我們的介面方法不帶任何引數,我們可以用空括號替換宣告:

() -> System.out.println("anything");

不如我們直接內聯 lambda,而不先建立一個物件,然後將它傳遞給 saySomething 方法:

public static void main(String[] args) {
    LambdaDemo demo = new LambdaDemo();
    String something="I am Lambda";
    /**/
    demo.printSomething(something, toPrint -> System.out.println(toPrint));
}

現在我們真的開始談論函數語言程式設計了。 我們最初的九行主體現在減少到只有 3 行。 這種程式碼的緊湊性使得 lambda 表示式對 Java 程式設計師非常有吸引力。

 

相關文章