一文徹底掌握Java中的Lambda表達式
為什么需要 Lambda 表達式?
Lambda表達式是Java函數(shù)式編程的核心概念之一。同時它也是一個相對難以理解的概念。
那么為什么需要它呢?
Lambda 表達式的出現(xiàn)是為了簡化實現(xiàn)函數(shù)式接口 Functional Interface 的,什么又是函數(shù)式接口呢?
因此再講函數(shù)式接口之前,先來回顧一下 interface 的概念與基本使用。
interface 接口

接口是用來定義一個協(xié)議或約定,它只聲明方法但不提供方法的具體實現(xiàn)。
我們稱這樣的方法為抽象方法 Abstract Method 。
具體方法的實現(xiàn)是由實現(xiàn)這個接口的 class 來提供的:

這樣一來將接口的聲明與具體實現(xiàn)分開,業(yè)務(wù)中就只需要關(guān)心方法,而不需要關(guān)心具體的實現(xiàn)類,從而實現(xiàn)代碼的解耦與模塊化。
假如現(xiàn)在有一個需求,通過一個方法來發(fā)送多種不同類型的消息,比如既可以發(fā)送 Email 消息也可以發(fā)送 SMS 短信消息,這種場景就非常適合使用 Interface 來實現(xiàn)。
我們先定義一個消息發(fā)送的接口:
/**
* @author TheSea
* @description 消息接口
* @createDate 2025/12/28
*/
public interface Message {
void send();
}接下來創(chuàng)建一個 Email 類來實現(xiàn)這個 Message 接口:
/**
* @author TheSea
* @description 郵件消息類
* @createDate 2025/12/28
*/
public class Email implements Message{
private String email;
@Override
public void send() {
System.out.println("這是一份郵件消息.");
}
}
再來創(chuàng)建一個 Sms 類來實現(xiàn)這個 Message 接口:
/**
* @author TheSea
* @description 短信消息類
* @createDate 2025/12/28
*/
public class Sms implements Message{
private String phone;
@Override
public void send() {
System.out.println("這是一份手機短信消息.");
}
}
現(xiàn)在我們來發(fā)送郵件消息,寫一個方法用來負責統(tǒng)一發(fā)送消息:
// 參數(shù)類型為接口,因為參數(shù)類型為 Message 接口類型,
// 這就意味著不管傳入的是 Email 還是 Sms 對象,
// 它們的類都已經(jīng)各自實現(xiàn)了 Message 接口的 send 方法
// 所以 sendMsg 方法內(nèi)部只需要執(zhí)行 message 的 send 方法
// 而不需要關(guān)心執(zhí)行的到底是哪個對象的 send 方法
// 免去了復雜的判斷和切換,這就是面向接口編程的一個典型應(yīng)用場景
public static void sendMsg(Message message){
message.send();
}
現(xiàn)在嘗試發(fā)送郵件消息:
public class Main {
public static void main(String[] args) {
//發(fā)送郵件消息
Message emailMessage = new Email();
sendMsg(emailMessage);
}
// 參數(shù)類型為接口,因為參數(shù)類型為 Message 接口類型,
// 這就意味著不管傳入的是 Email 還是 Sms 對象,
// 它們的類都已經(jīng)各自實現(xiàn)了 Message 接口的 send 方法
// 所以 sendMsg 方法內(nèi)部只需要執(zhí)行 message 的 send 方法
// 而不需要關(guān)心執(zhí)行的到底是哪個對象的 send 方法
// 免去了復雜的判斷和切換,這就是面向接口編程的一個典型應(yīng)用場景
public static void sendMsg(Message message){
message.send();
}
}

再來嘗試一下發(fā)送 Sms 消息:
public class Main {
public static void main(String[] args) {
//發(fā)送短信消息
Message smsMessage = new Sms();
sendMsg(smsMessage);
}
// 參數(shù)類型為接口,因為參數(shù)類型為 Message 接口類型,
// 這就意味著不管傳入的是 Email 還是 Sms 對象,
// 它們的類都已經(jīng)各自實現(xiàn)了 Message 接口的 send 方法
// 所以 sendMsg 方法內(nèi)部只需要執(zhí)行 message 的 send 方法
// 而不需要關(guān)心執(zhí)行的到底是哪個對象的 send 方法
// 免去了復雜的判斷和切換,這就是面向接口編程的一個典型應(yīng)用場景
public static void sendMsg(Message message){
message.send();
}
}

到這里按照傳統(tǒng)方法,我們已經(jīng)正確的實現(xiàn)和使用了接口,應(yīng)用場景也 OK。
問題的引入
但是我們會發(fā)現(xiàn),要發(fā)送一條消息要經(jīng)過好多個步驟,比如我們發(fā)送 Sms 消息。
我們需要先創(chuàng)建一個 Sms 類,然后去實現(xiàn) Message 接口中的 send() 方法,然后再實例化一個 Sms 對象,再調(diào)用 send 發(fā)送消息,非常繁復。
而 Lambda 表達式的出現(xiàn)就可以幫助我們解決這個問題。
Lambda 表達式
Lambda 表達式可以提供一種簡單快速的方式來實現(xiàn)上述接口,接口的抽象方法的具體實現(xiàn)直接在 Lambda 表達式里面定義即可,而不用像傳統(tǒng)方法那樣創(chuàng)建類然后實現(xiàn)接口的抽象方法、實例化對象最后調(diào)用方法,大大簡化了代碼的編寫流程。
接下來用 Lambda 表達式重新實現(xiàn)一下剛才的例子。
public class Main {
public static void main(String[] args) {
// send()方法的實現(xiàn):
// public void send() {
// System.out.println("這是一份郵件消息.");
// }
// Lambda 表達式可以直接可以直接實現(xiàn) Message 接口的 send 抽象方法,然后作為參數(shù)傳給 sendMessage
// () 代表的就是 send() 方法后面的括號,即參數(shù)列表
// {} 大括號里面的內(nèi)容就是 send() 方法的函數(shù)體
sendMsg(() ->{
System.out.println("這是一份郵件消息.");
});
}
// 參數(shù)類型為接口,因為參數(shù)類型為 Message 接口類型,
// 這就意味著不管傳入的是 Email 還是 Sms 對象,
// 它們的類都已經(jīng)各自實現(xiàn)了 Message 接口的 send 方法
// 所以 sendMsg 方法內(nèi)部只需要執(zhí)行 message 的 send 方法
// 而不需要關(guān)心執(zhí)行的到底是哪個對象的 send 方法
// 免去了復雜的判斷和切換,這就是面向接口編程的一個典型應(yīng)用場景
public static void sendMsg(Message message){
message.send();
}
}
上面這條 Lambda 表達式就等效于之前用傳統(tǒng)方法實現(xiàn)的 Email 實例對象。

如果 Lambda 的函數(shù)體里只包含一個表達式,那么可以省略大括號進行簡寫:
sendMsg(() -> System.out.println("這是一份郵件消息."));
如果 Lambda 表達式包含多條語句或者需要明確的流程控制,那么就必須要使用大括號。
目前的例子中抽象方法并沒有參數(shù),現(xiàn)在假設(shè)抽象方法有一個參數(shù) name:
public interface Message {
void send(String name);
}
那么 Lambda 表達式中就需要這么定義:
public class Main {
public static void main(String[] args) {
sendMsg((name) -> System.out.println(name + ": 這是一份郵件消息."));
}
public static void sendMsg(Message message){
message.send("TheSea");
}
}

注意上面的 參數(shù)名 是形參,可以隨便寫,不一定要和接口中聲明的一樣,比如這樣寫也是一樣的效果:
sendMsg((nameInLambda) -> System.out.println(nameInLambda + ": 這是一份郵件消息."));
如果參數(shù)只有一個的話,Lambda 表達式的參數(shù)列表的小括號是可以去掉的:
sendMsg(name -> System.out.println(name + ": 這是一份郵件消息."));
那么如果有多個參數(shù)呢?那就按順序書寫,然后中間用逗號分隔即可,注意必須要帶上小括號嗷:
public interface Message {
void send(String name, int age);
}
public class Main {
public static void main(String[] args) {
sendMsg((name, age) -> System.out.println(name + ": 您" + age + "歲了,這是一份郵件消息."));
}
public static void sendMsg(Message message) {
message.send("TheSea", 18);
}
}

注意一定要參數(shù)的聲明順序書寫編譯器才能對上號,否則的話會出現(xiàn)下面的荒唐局面:
public class Main {
public static void main(String[] args) {
sendMsg((age, name) -> System.out.println(name + ": 您" + age + "歲了,這是一份郵件消息."));
}
public static void sendMsg(Message message) {
message.send("TheSea", 18);
}
}

以上示例的抽象方法都沒有返回值,我們來看一下有返回值的情況:
public interface Message {
String send(String name, int age);
}
此時我們之前的 Lambda 表達式就會報錯:

因為我們需要有返回值:

可以看到,如果函數(shù)體只有一條返回語句,像上面這樣寫會報錯,原因是如果只有一條返回語句的話,return 關(guān)鍵字是不需要存在的,可以簡化成下面這樣:
public class Main {
public static void main(String[] args) {
sendMsg((age, name) -> "Lambda 表達式的返回值");
}
public static void sendMsg(Message message) {
String res = message.send("TheSea", 18);
System.out.println(res);
}
}
現(xiàn)在把參數(shù)應(yīng)用進去,當函數(shù)體有多條表達式的時候,需要用大括號包圍:
public class Main {
public static void main(String[] args) {
sendMsg((name, age) -> {
System.out.println(name + ": 您" + age + "歲了,這是一份郵件消息.");
return "Lambda 表達式的返回值";
});
}
public static void sendMsg(Message message) {
String res = message.send("TheSea", 18);
System.out.println(res);
}
}

另外如果現(xiàn)在我們想改另外一種發(fā)送方式,比如使用 Sms,那么我們現(xiàn)在也不需要再新建一個 Sms 類來實現(xiàn)接口了,直接修改 Lambda 表達式的函數(shù)體就可以:
public class Main {
public static void main(String[] args) {
sendMsg((name, age) -> {
System.out.println(name + ": 您" + age + "歲了,這是一份短信消息.");
return "Lambda 表達式的返回值";
});
}
public static void sendMsg(Message message) {
String res = message.send("TheSea", 18);
System.out.println(res);
}
}

Lambda 表達式也可以像普通對象那樣賦值給變量,如下:
public class Main {
public static void main(String[] args) {
Message lambda = (name, age) -> {
System.out.println(name + ": 您" + age + "歲了,這是一份短信消息.");
return "Lambda 表達式的返回值";
};
sendMsg(lambda);
}
public static void sendMsg(Message message) {
String res = message.send("TheSea", 18);
System.out.println(res);
}
}
綜上所述,Lambda 讓我們實現(xiàn)接口抽象方法的整個過程變得非常簡單。
那么 Lambda 表達式是不是可以應(yīng)用在任何形式的 interface 上呢?
當然不行!
Lambda 表達式只能應(yīng)用于有且只有一個抽象方法的接口上,我們稱這樣的接口為函數(shù)式接口。
那為什么Java要這么定義呢?
因為一個接口如果有多個抽象方法的話,那么在使用 Lambda 表達式的時候 Java 將無法確定 Lambda 試圖實現(xiàn)哪一個抽象方法,而當只有一個抽象方法的時候?qū)τ?Java 來說意圖就非常明確。
因此只有函數(shù)式接口才可以使用 Lambda 表達式。
另外,我們可以使用 @FunctionalInterface 注解來標識該接口為一個函數(shù)式接口:
@FunctionalInterface
public interface Message {
String send(String name, int age);
}
這個注解是可選的,因為函數(shù)式接口定義的本身并不依賴于這個注解,即便不標注但只要符合函數(shù)式接口的定義條件,Java自動就會把它當成是函數(shù)式接口。
不過工程開發(fā)中我們還是建議使用該注解來進行標識,這樣的話如果出現(xiàn)多余一個抽象方法或者是沒有抽象方法的時候就會編譯報錯,同時也會提供一個非常好的語義方便工程師更好的理解該接口的設(shè)計意圖。
總結(jié)
Lambda 表達式歸根到底是一種語法糖,用于簡化函數(shù)式接口的實現(xiàn)。
在 Java 的函數(shù)式編程中起到了關(guān)鍵的作用,Java 標準庫中也包含了非常多的內(nèi)置的函數(shù)式接口,比如 Predicate、Function、Consumer、Supplier 等等,經(jīng)常與 Stream API 結(jié)合使用。
所以掌握 Lambda 表達式是非常重要的。
到此這篇關(guān)于Java中Lambda表達式的文章就介紹到這了,更多相關(guān)Java中Lambda表達式內(nèi)容請搜索腳本之家以前的文章或繼續(xù)瀏覽下面的相關(guān)文章希望大家以后多多支持腳本之家!
相關(guān)文章
java實現(xiàn)連接mysql數(shù)據(jù)庫單元測試查詢數(shù)據(jù)的實例代碼
下面小編就為大家?guī)硪黄猨ava實現(xiàn)連接mysql數(shù)據(jù)庫單元測試查詢數(shù)據(jù)的實例代碼。小編覺得挺不錯的,現(xiàn)在就分享給大家,也給大家做個參考。一起跟隨小編過來看看吧2016-10-10
springboot2中session超時,退到登錄頁面方式
這篇文章主要介紹了springboot2中session超時,退到登錄頁面方式,具有很好的參考價值,希望對大家有所幫助。如有錯誤或未考慮完全的地方,望不吝賜教2022-01-01
Java構(gòu)造方法實例詳解(動力節(jié)點java學院整理)
其實java構(gòu)造方法很簡單,下面通過示例給大家分享java構(gòu)造方法,非常不錯,具有參考借鑒價值,需要的朋友參考下2017-04-04
springboot中@RequestParam和@PathVariable區(qū)別
本文主要介紹了springboot中@RequestParam和@PathVariable區(qū)別,文中通過示例代碼介紹的非常詳細,對大家的學習或者工作具有一定的參考學習價值,需要的朋友們下面隨著小編來一起學習學習吧2025-07-07

