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

注意:Collection的forEach()方法是從接口 java.lang.Iterable 拿過來的。
Collection接口
forEach() 方法演示
該方法在接口 Iterable 當(dāng)中,原型如下
default void forEach(Consumer<? super T> action) {
Objects.requireNonNull(action);
for (T t : this) {
action.accept(t);
}
}該方法表示:對(duì)容器中的每個(gè)元素執(zhí)行action指定的動(dòng)作 。
public static void main(String[] args) {
ArrayList<String> list = new ArrayList<>();
list.add("Hello");
list.add("腳本之家");
list.add("hello");
list.add("網(wǎng)站");
list.forEach(new Consumer<String>(){
@Override
public void accept(String str){
//簡(jiǎn)單遍歷集合中的元素。
System.out.print(str+" ");
}
});輸出結(jié)果:Hello 腳本之家 hello 網(wǎng)站
我們可以修改為如下代碼:
public static void main(String[] args) {
ArrayList<String> list = new ArrayList<>();
list.add("Hello");
list.add("腳本之家");
list.add("hello");
list.add("網(wǎng)站");
//表示調(diào)用一個(gè),不帶有參數(shù)的方法,其執(zhí)行花括號(hào)內(nèi)的語句,為原來的函數(shù)體內(nèi)容。
list.forEach(s -> {
System.out.println(s);
});
}輸出結(jié)果:Hello 腳本之家 hello 網(wǎng)站
List接口
sort()方法的演示
sort方法源碼:該方法根據(jù)c指定的比較規(guī)則對(duì)容器元素進(jìn)行排序。
public void sort(Comparator<? super E> c) {
final int expectedModCount = modCount;
Arrays.sort((E[]) elementData, 0, size, c);
if (modCount != expectedModCount) {
throw new ConcurrentModificationException();
}
modCount++;
}使用示例:
public static void main(String[] args) {
ArrayList<String> list = new ArrayList<>();
list.add("Hello");
list.add("腳本之家");
list.add("hello");
list.add("網(wǎng)站");
list.sort(new Comparator<String>() {
@Override
public int compare(String str1, String str2){
//注意這里比較長(zhǎng)度
return str1.length()-str2.length();
}
});
System.out.println(list);
}輸出結(jié)果:腳本之家, Hello, hello, 網(wǎng)站
修改為lambda表達(dá)式:
public static void main(String[] args) {
ArrayList<String> list = new ArrayList<>();
list.add("Hello");
list.add("腳本之家");
list.add("hello");
list.add("網(wǎng)站");
//調(diào)用帶有2個(gè)參數(shù)的方法,且返回長(zhǎng)度的差值
list.sort((str1,str2)-> str1.length()-str2.length());
System.out.println(list);
}輸出結(jié)果:腳本之家, Hello, hello, 網(wǎng)站
Map接口
HashMap 的 forEach()
該方法原型如下:
default void forEach(BiConsumer<? super K, ? super V> action) {Objects.requireNonNull(action);
for (Map.Entry<K, V> entry : entrySet()) {
K k;
V v;
try {
k = entry.getKey();
v = entry.getValue();
} catch(IllegalStateException ise) {
// this usually means the entry is no longer in the map.
throw new ConcurrentModificationException(ise);
}
action.accept(k, v);
}
}作用是對(duì)Map中的每個(gè)映射執(zhí)行action指定的操作。
代碼示例:
public static void main(String[] args) {
HashMap<Integer, String> map = new HashMap<>();
map.put(1, "hello");
map.put(2, "腳本之家");
map.put(3, "hello");
map.put(4, "網(wǎng)站");
map.forEach(new BiConsumer<Integer, String>(){
@Override
public void accept(Integer k, String v){
System.out.println(k + "=" + v);
}
});
}輸出結(jié)果:
1=hello 2=腳本之家 3=hello 4=網(wǎng)站
使用lambda表達(dá)式后的代碼:
public static void main(String[] args) {
HashMap<Integer, String> map = new HashMap<>();
map.put(1, "hello");
map.put(2, "腳本之家");
map.put(3, "hello");
map.put(4, "網(wǎng)站");
map.forEach((k,v)-> System.out.println(k + "=" + v));
}輸出結(jié)果:
1=hello 2=腳本之家 3=hello 4=網(wǎng)站
Lambda表達(dá)式總結(jié)
Lambda表達(dá)式的優(yōu)點(diǎn)很明顯,在代碼層次上來說,使代碼變得非常的簡(jiǎn)潔。缺點(diǎn)也很明顯,代碼不易讀。
優(yōu)點(diǎn):
- 代碼簡(jiǎn)潔,開發(fā)迅速
- 方便函數(shù)式編程
- 非常容易進(jìn)行并行計(jì)算
- Java 引入 Lambda,改善了集合操作
缺點(diǎn):
- 代碼可讀性變差
- 在非并行計(jì)算中,很多計(jì)算未必有傳統(tǒng)的 for 性能要高
- 不容易進(jìn)行調(diào)試
到此這篇關(guān)于JavaSE中Lambda表達(dá)式的使用與變量捕獲的文章就介紹到這了,更多相關(guān)JavaSE Lambda表達(dá)式內(nèi)容請(qǐng)搜索腳本之家以前的文章或繼續(xù)瀏覽下面的相關(guān)文章希望大家以后多多支持腳本之家!
相關(guān)文章
java httpclient設(shè)置超時(shí)時(shí)間和代理的方法
這篇文章主要介紹了java httpclient設(shè)置超時(shí)時(shí)間和代理的方法,文中通過示例代碼介紹的非常詳細(xì),對(duì)大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價(jià)值,需要的朋友們下面隨著小編來一起學(xué)習(xí)學(xué)習(xí)吧2020-02-02
解決Java編譯時(shí)錯(cuò)誤:A JNI error has occurred,ple
這篇文章主要介紹了解決Java編譯時(shí)錯(cuò)誤:A JNI error has occurred,please check your installation and try again,具有很好的參考價(jià)值,希望對(duì)大家有所幫助,如有錯(cuò)誤或未考慮完全的地方,望不吝賜教2024-02-02
JavaWeb實(shí)現(xiàn)文件上傳與下載實(shí)例詳解
在Web應(yīng)用程序開發(fā)中,文件上傳與下載功能是非常常用的功能,下面通過本文給大家介紹JavaWeb實(shí)現(xiàn)文件上傳與下載實(shí)例詳解,對(duì)javaweb文件上傳下載相關(guān)知識(shí)感興趣的朋友一起學(xué)習(xí)吧2016-02-02
五分鐘帶你學(xué)會(huì)用java解析json字符串
這篇文章主要給大家介紹了關(guān)于用java解析json字符串的相關(guān)資料,JSON是一種輕量級(jí)的、基于文本的、與語言無關(guān)的數(shù)據(jù)交換格式,易于人和機(jī)器讀寫,文中通過實(shí)例代碼介紹的非常詳細(xì),需要的朋友可以參考下2023-07-07
Idea中springboot項(xiàng)目的熱部署無法生效問題解決
本文主要介紹了Idea中springboot項(xiàng)目的熱部署無法生效問題解決,文中通過示例代碼介紹的非常詳細(xì),對(duì)大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價(jià)值,需要的朋友們下面隨著小編來一起學(xué)習(xí)學(xué)習(xí)吧2023-10-10
使用MyBatis-Plus實(shí)現(xiàn)聯(lián)表查詢分頁的示例代碼
本文主要講述了如何在SpringBoot項(xiàng)目中使用MyBatis-Plus的分頁插件,通過這個(gè)示例,可以學(xué)會(huì)如何利用MyBatis-Plus進(jìn)行高效的分頁查詢,感興趣的可以了解一下2024-10-10
mybatis mapper.xml獲取insert后的自增ID問題
這篇文章主要介紹了mybatis mapper.xml獲取insert后的自增ID問題,具有很好的參考價(jià)值,希望對(duì)大家有所幫助,如有錯(cuò)誤或未考慮完全的地方,望不吝賜教2024-05-05

