Java Lambda表達(dá)式超詳細(xì)介紹
一、背景
Lambda表達(dá)式是Java SE 8中一個重要的新特性。lambda表達(dá)式允許你通過表達(dá)式來代替功能接口。 lambda表達(dá)式就和方法一樣,它提供了一個正常的參數(shù)列表和一個使用這些參數(shù)的主體(body,可以是一個表達(dá)式或一個代碼
塊)。 Lambda 表達(dá)式(Lambda expression)可以看作是一個匿名函數(shù),基于數(shù)學(xué)中的λ演算得名,也可稱為閉包(Closure)
1.Lambda表達(dá)式的語法
基本語法: (parameters) -> expression 或 (parameters) ->{ statements; }
Lambda表達(dá)式由三部分組成:
- 1.paramaters:類似方法中的形參列表,這里的參數(shù)是函數(shù)式接口里的參數(shù)。這里的參數(shù)類型可以明確的聲明 也可不聲明而由JVM隱含的推斷。另外當(dāng)只有一個推斷類型時可以省略掉圓括號。
- 2.->:可理解為“被用于”的意思
- 3.方法體:可以是表達(dá)式也可以代碼塊,是函數(shù)式接口里方法的實現(xiàn)。代碼塊可返回一個值或者什么都不反 回,這里的代碼塊塊等同于方法的方法體。如果是表達(dá)式,也可以返回一個值或者什么都不反回。
// 1. 不需要參數(shù),返回值為 2 ()->2 // 2. 接收一個參數(shù)(數(shù)字類型),返回其2倍的值 x->2*x // 3. 接受2個參數(shù)(數(shù)字),并返回他們的和 (x,y) -> x+y // 4. 接收2個int型整數(shù),返回他們的乘積 (int x,int y) -> x * y // 5. 接受一個 string 對象,并在控制臺打印,不返回任何值(看起來像是返回void) (String s) -> System.out.print(s)
2.函數(shù)式接口
要了解Lambda表達(dá)式,首先需要了解什么是函數(shù)式接口,函數(shù)式接口定義:一個接口有且只有一個抽象方法 。
注意:
1.如果一個接口只有一個抽象方法,那么該接口就是一個函數(shù)式接口
2.如果我們在某個接口上聲明了@FunctionalInterface注解,那么編譯器就會按照函數(shù)式接口的定義來要求該接口,這樣如果有兩個抽象方法,程序編譯就會報錯的。所以,從某種意義上來說,只要你保證你的接口 中只有一個抽象方法,你可以不加這個注解。加上就會自動進(jìn)行檢測的。
定義方式:
@FunctionalInterface
interface NoParameterNoReturn {
? ? //注意:只能有一個抽象方法
? ? void test();
}但是這種方式也是可以的:
@FunctionalInterface
interface NoParameterNoReturn {
? ? void test();
? ? default void test2() {
? ? ? ? System.out.println("JDK1.8新特性,default默認(rèn)方法可以有具體的實現(xiàn)");
? ? }
}二、Lambda表達(dá)式的基本使用
首先,我們實現(xiàn)準(zhǔn)備好幾個接口:
@FunctionalInterface
interface NoParameterNoReturn {
? ? //注意:只能有一個抽象方法
? ? void test();
}
//無返回值一個參數(shù)
@FunctionalInterface
interface OneParameterNoReturn {
? ? void test(int a);
}
//無返回值多個參數(shù)
@FunctionalInterface
interface MoreParameterNoReturn {
? ? void test(int a, int b);
}
//有返回值無參數(shù)
@FunctionalInterface
interface NoParameterReturn {
? ? int test();
}
//有返回值一個參數(shù)
@FunctionalInterface
interface OneParameterReturn {
? ? int test(int a);
}
//有返回值多參數(shù)
@FunctionalInterface
interface MoreParameterReturn {
? ? int test(int a, int b);
}我們在上面提到過,Lambda表達(dá)式本質(zhì)是一個匿名函數(shù),函數(shù)的方法是:返回值 方法名 參數(shù)列表 方法體。在,Lambda表達(dá)式中我們只需要關(guān)心:參數(shù)列表 方法體。
具體使用見以下示例代碼:
@FunctionalInterface
interface NoParameterNoReturn {
? ? //注意:只能有一個抽象方法
? ? void test();
}
//無返回值一個參數(shù)
@FunctionalInterface
interface OneParameterNoReturn {
? ? void test(int a);
}
//無返回值多個參數(shù)
@FunctionalInterface
interface MoreParameterNoReturn {
? ? void test(int a, int b);
}
//有返回值無參數(shù)
@FunctionalInterface
interface NoParameterReturn {
? ? int test();
}
//有返回值一個參數(shù)
@FunctionalInterface
interface OneParameterReturn {
? ? int test(int a);
}
//有返回值多參數(shù)
@FunctionalInterface
interface MoreParameterReturn {
? ? int test(int a, int b);
}
public class TestDemo2 {
? ? public static void main(String[] args) {
? ? ? ? NoParameterNoReturn noParameterNoReturn = () -> {
? ? ? ? ? ? System.out.println("無參數(shù)無返回值");
? ? ? ? };
? ? ? ? //test方法的主體內(nèi)容在上述括號內(nèi)
? ? ? ? noParameterNoReturn.test();
? ? ? ? OneParameterNoReturn oneParameterNoReturn = (int a) -> {
? ? ? ? ? ? System.out.println("無參數(shù)一個返回值:" + a);
? ? ? ? };
? ? ? ? oneParameterNoReturn.test(10);
? ? ? ? MoreParameterNoReturn moreParameterNoReturn = (int a, int b) -> {
? ? ? ? ? ? System.out.println("無返回值多個參數(shù):" + a + " " + b);
? ? ? ? };
? ? ? ? moreParameterNoReturn.test(20, 30);
? ? ? ? NoParameterReturn noParameterReturn = () -> {
? ? ? ? ? ? System.out.println("有返回值無參數(shù)!");
? ? ? ? ? ? return 40;
? ? ? ? };
? ? ? ? //接收函數(shù)的返回值
? ? ? ? int ret = noParameterReturn.test();
? ? ? ? System.out.println(ret);
? ? ? ? OneParameterReturn oneParameterReturn = (int a) -> {
? ? ? ? ? ? System.out.println("有返回值有參數(shù)!");
? ? ? ? ? ? return a;
? ? ? ? };
? ? ? ? ret = oneParameterReturn.test(50);
? ? ? ? System.out.println(ret);
? ? ? ? MoreParameterReturn moreParameterReturn = (int a, int b) -> {
? ? ? ? ? ? System.out.println("有返回值多個參數(shù)!");
? ? ? ? ? ? return a + b;
? ? ? ? };
? ? ? ? ret = moreParameterReturn.test(60, 70);
? ? ? ? System.out.println(ret);
? ? }
}三、語法精簡
- 參數(shù)類型可以省略,如果需要省略,每個參數(shù)的類型都要省略。
- 參數(shù)的小括號里面只有一個參數(shù),那么小括號可以省略
- 如果方法體當(dāng)中只有一句代碼,那么大括號可以省略
- 如果方法體中只有一條語句,其是return語句,那么大括號可以省略,且去掉return關(guān)鍵字。
示例代碼:
@FunctionalInterface
interface NoParameterNoReturn {
? ? //注意:只能有一個抽象方法
? ? void test();
}
//無返回值一個參數(shù)
@FunctionalInterface
interface OneParameterNoReturn {
? ? void test(int a);
}
//無返回值多個參數(shù)
@FunctionalInterface
interface MoreParameterNoReturn {
? ? void test(int a, int b);
}
//有返回值無參數(shù)
@FunctionalInterface
interface NoParameterReturn {
? ? int test();
}
//有返回值一個參數(shù)
@FunctionalInterface
interface OneParameterReturn {
? ? int test(int a);
}
//有返回值多參數(shù)
@FunctionalInterface
interface MoreParameterReturn {
? ? int test(int a, int b);
}
public class TestDemo2 {
? ? public static void main(String[] args) {
? ? ? ? //方法參數(shù)有多個且方法體中無返回值,則可以省略參數(shù)類型
? ? ? ? MoreParameterNoReturn moreParameterNoReturn = (a, b) -> {
? ? ? ? ? ? System.out.println("無返回值多個參數(shù),省略參數(shù)類型:" + a + " " + b);
? ? ? ? };
? ? ? ? moreParameterNoReturn.test(20, 30);
? ? ? ? //方法中只有一個參數(shù),那么小括號可以省略
? ? ? ? OneParameterNoReturn oneParameterNoReturn = a -> {
? ? ? ? ? ? System.out.println("方法中只有一個參數(shù),那么小括號可以省略:" + a);
? ? ? ? };
? ? ? ? oneParameterNoReturn.test(10);
? ? ? ? //無參數(shù)無返回值,方法體中只有 一行代碼的時候,可以去掉方法體的大括號
? ? ? ? NoParameterNoReturn noParameterNoReturn = () -> System.out.println("無參數(shù)無返回值,方法體中只有 一行代碼");
? ? ? ? noParameterNoReturn.test();
? ? ? ? //方法體中只有一條語句,且是return語句,且無參數(shù)
? ? ? ? NoParameterReturn noParameterReturn = () -> 40;
? ? ? ? int ret = noParameterReturn.test();
? ? ? ? System.out.println(ret);
? ? }
}四、變量捕獲
Lambda 表達(dá)式中存在變量捕獲 ,了解了變量捕獲之后,我們才能更好的理解Lambda 表達(dá)式的作用域 。Java當(dāng)中的匿名類中,會存在變量捕獲。
下面我們來講下在Lambda當(dāng)中也可以進(jìn)行變量的捕獲,具體我們看一下代碼:
@FunctionalInterface
interface NoParameterNoReturn {
? ? void test();
}
public class TestDemo2 {
? ? public static void main(String[] args) {
? ? ? ? int a = 10;
? ? ? ? NoParameterNoReturn noParameterNoReturn = () -> {
? ? ? ? ? ? /*
? ? ? ? ? ? 注意此處不能夠修改a的值,與匿名內(nèi)部類中相同
? ? ? ? ? ? a = 99;
? ? ? ? ? ? */
? ? ? ? ? ? System.out.println("捕獲變量:" + a);
? ? ? ? };
? ? ? ? noParameterNoReturn.test();
? ? }
}五、Lambda在集合當(dāng)中的使用
為了能夠讓Lambda和Java的集合類集更好的一起使用,集合當(dāng)中,也新增了部分接口,以便與Lambda表達(dá)式對接。

以上方法的作用可自行查看我們發(fā)的幫助手冊。我們這里會示例一些方法的使用。注意:Collection的forEach()方法是從接口 java.lang.Iterable 拿過來的。
1.Collection接口
forEach() 方法演示
該方法在接口 Iterable 當(dāng)中,原型如下:

**forEach()**方法表示:對容器中的每個元素執(zhí)行action指定的動作
可以看到我們的參數(shù)Consumer其實是一個函數(shù)式接口:

這個函數(shù)式接口中有一個抽象方法accept:

public class TestDemo2 {
? ? public static void main(String[] args) {
? ? ? ? ArrayList<String> list = new ArrayList<>();
? ? ? ? list.add("Hello");
? ? ? ? list.add("bit");
? ? ? ? list.add("hello");
? ? ? ? list.add("lambda");
? ? ? ? list.forEach(new Consumer<String>() {
? ? ? ? ? ? @Override
? ? ? ? ? ? public void accept(String s) {
? ? ? ? ? ? ? ? //簡單遍歷集合中的元素
? ? ? ? ? ? ? ? System.out.println(s);
? ? ? ? ? ? }
? ? ? ? });
? ? }
}輸出結(jié)果:
Hello bit hello lambda
我們可以修改為如下代碼:
public class TestDemo2 {
? ? public static void main(String[] args) {
? ? ? ? ArrayList<String> list = new ArrayList<>();
? ? ? ? list.add("Hello");
? ? ? ? list.add("bit");
? ? ? ? list.add("hello");
? ? ? ? list.add("lambda");
? ? ?
? ? ? ? ?list.forEach((String s) -> {
? ? ? ? ? ? System.out.println(s);
? ? ? ? });
? ? }
}同時還可以簡化代碼:
public class TestDemo2 {
? ? public static void main(String[] args) {
? ? ? ? ArrayList<String> list = new ArrayList<>();
? ? ? ? list.add("Hello");
? ? ? ? list.add("bit");
? ? ? ? list.add("hello");
? ? ? ? list.add("lambda");
? ? ? ? list.forEach(s -> System.out.println(s));
? ? }
}六、List接口
1.sort()方法的演示
sort方法源碼:該方法根據(jù)c指定的比較規(guī)則對容器元素進(jìn)行排序。
可以看到其參數(shù)是Comparator,我們點進(jìn)去看下:又是一個函數(shù)式接口

這個接口中有一個抽象方法叫做compare方法:

使用示例:
public class TestDemo2 {
? ? public static void main(String[] args) {
? ? ? ? ArrayList<String> list = new ArrayList<>();
? ? ? ? list.add("Hello");
? ? ? ? list.add("bit");
? ? ? ? list.add("hello");
? ? ? ? list.add("lambda");
? ? ? ? /*
? ? ? ? 對list集合中的字符串按照長度進(jìn)行排序
? ? ? ? ?*/
? ? ? ? list.sort(new Comparator<String>() {
? ? ? ? ? ? @Override
? ? ? ? ? ? public int compare(String o1, String o2) {
? ? ? ? ? ? ? ? return o1.length() - o2.length();
? ? ? ? ? ? }
? ? ? ? });
? ? ? ? /*
? ? ? ? 輸出排序后最終的結(jié)果
? ? ? ? ?*/
? ? ? ? list.forEach(s -> System.out.println(s));
? ? }
}輸出結(jié)果為:
bit Hello hello lambda
修改為lambda表達(dá)式:
public class TestDemo2 {
? ? public static void main(String[] args) {
? ? ? ? ArrayList<String> list = new ArrayList<>();
? ? ? ? list.add("Hello");
? ? ? ? list.add("bit");
? ? ? ? list.add("hello");
? ? ? ? list.add("lambda");
? ? ? ? /*
? ? ? ? 對list集合中的字符串按照長度進(jìn)行排序
? ? ? ? ?*/
? ? ? ? list.sort((String o1, String o2) -> {
? ? ? ? ? ? ? ? ? ? return o1.length() - o2.length();
? ? ? ? ? ? ? ? }
? ? ? ? );
? ? ? ? /*
? ? ? ? 輸出排序后最終的結(jié)果:
? ? ? ? bit
? ? ? ? Hello
? ? ? ? hello
? ? ? ? lambda
? ? ? ? ?*/
? ? ? ? list.forEach(s -> System.out.println(s));
? ? }
}此時還可以對代碼進(jìn)行簡化:
public class TestDemo2 {
? ? public static void main(String[] args) {
? ? ? ? ArrayList<String> list = new ArrayList<>();
? ? ? ? list.add("Hello");
? ? ? ? list.add("bit");
? ? ? ? list.add("hello");
? ? ? ? list.add("lambda");
? ? ? ? /*
? ? ? ? 對list集合中的字符串按照長度進(jìn)行排序
? ? ? ? ?*/
? ? ? ? list.sort((o1, o2) ->
? ? ? ? ? ? ? ? o1.length() - o2.length()
? ? ? ? );
? ? ? ? /*
? ? ? ? 輸出排序后最終的結(jié)果:
? ? ? ? bit
? ? ? ? Hello
? ? ? ? hello
? ? ? ? lambda
? ? ? ? ?*/
? ? ? ? list.forEach(s -> System.out.println(s));
? ? }
}七、Map接口
HashMap 的 forEach()方法:

這個函數(shù)式接口中有一個抽象方法叫做accept方法:

代碼示例:
public class TestDemo2 {
? ? public static void main(String[] args) {
? ? ? ? HashMap<Integer, String> map = new HashMap<>();
? ? ? ? map.put(1, "hello");
? ? ? ? map.put(2, "bit");
? ? ? ? map.put(3, "hello");
? ? ? ? map.put(4, "lambda");
? ? ? ? map.forEach(new BiConsumer<Integer, String>() {
? ? ? ? ? ? @Override
? ? ? ? ? ? public void accept(Integer integer, String s) {
? ? ? ? ? ? ? ? System.out.println(integer + " " + s);
? ? ? ? ? ? }
? ? ? ? });
? ? }
}輸出結(jié)果:
1 hello
2 bit
3 hello
4 lambda
使用lambda表達(dá)式后的代碼:
public class TestDemo2 {
? ? public static void main(String[] args) {
? ? ? ? HashMap<Integer, String> map = new HashMap<>();
? ? ? ? map.put(1, "hello");
? ? ? ? map.put(2, "bit");
? ? ? ? map.put(3, "hello");
? ? ? ? map.put(4, "lambda");
? ? ? ? map.forEach((Integer integer, String s) -> {
? ? ? ? ? ? ? ? ? ? System.out.println(integer + " " + s);
? ? ? ? ? ? ? ? }
? ? ? ? );
? ? }
}還可以對代碼繼續(xù)簡化:
public class TestDemo2 {
? ? public static void main(String[] args) {
? ? ? ? HashMap<Integer, String> map = new HashMap<>();
? ? ? ? map.put(1, "hello");
? ? ? ? map.put(2, "bit");
? ? ? ? map.put(3, "hello");
? ? ? ? map.put(4, "lambda");
? ? ? ? map.forEach((integer, s) ->
? ? ? ? ? ? ? ? System.out.println(integer + " " + s)
? ? ? ? );
? ? }
}總結(jié):
Lambda表達(dá)式的優(yōu)點很明顯,在代碼層次上來說,使代碼變得非常的簡潔。缺點也很明顯,代碼不易讀。
優(yōu)點:
代碼簡潔,開發(fā)迅速
方便函數(shù)式編程
非常容易進(jìn)行并行計算
Java 引入 Lambda,改善了集合操作
缺點:
代碼可讀性變差
在非并行計算中,很多計算未必有傳統(tǒng)的 for 性能要高
不容易進(jìn)行調(diào)試
相關(guān)文章
Java使用Collections工具類對List集合進(jìn)行排序
這篇文章主要介紹了Java使用Collections工具類對List集合進(jìn)行排序,文中通過示例代碼介紹的非常詳細(xì),對大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價值,需要的朋友可以參考下2019-10-10
Spring boot創(chuàng)建自定義starter的完整步驟
這篇文章主要給大家介紹了關(guān)于Spring boot創(chuàng)建自定義starter的相關(guān)資料,文中通過示例代碼介紹的非常詳細(xì),對大家學(xué)習(xí)或者使用Spring boot具有一定的參考學(xué)習(xí)價值,需要的朋友們下面來一起學(xué)習(xí)學(xué)習(xí)吧2019-09-09
Java基于二分搜索樹、鏈表的實現(xiàn)的集合Set復(fù)雜度分析實例詳解
這篇文章主要介紹了Java基于二分搜索樹、鏈表的實現(xiàn)的集合Set復(fù)雜度分析,結(jié)合實例形式詳細(xì)分析了Java基于二分搜索樹、鏈表的實現(xiàn)的集合Set復(fù)雜度分析相關(guān)操作技巧與注意事項,需要的朋友可以參考下2020-03-03
簡單了解Thymeleaf語法 數(shù)據(jù)延遲加載使用實例
這篇文章主要介紹了簡單了解Thymeleaf語法 數(shù)據(jù)延遲加載使用實例,文中通過示例代碼介紹的非常詳細(xì),對大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價值,需要的朋友可以參考下2010-05-05
java異常:異常處理--try-catch結(jié)構(gòu)詳解
今天小編就為大家分享一篇關(guān)于Java異常處理之try...catch...finally詳解,小編覺得內(nèi)容挺不錯的,現(xiàn)在分享給大家,具有很好的參考價值,需要的朋友一起跟隨小編來看看吧2021-09-09

