一区二区三区在线-一区二区三区亚洲视频-一区二区三区亚洲-一区二区三区午夜-一区二区三区四区在线视频-一区二区三区四区在线免费观看

服務器之家:專注于服務器技術及軟件下載分享
分類導航

PHP教程|ASP.NET教程|Java教程|ASP教程|編程技術|正則表達式|C/C++|IOS|C#|Swift|Android|VB|R語言|JavaScript|易語言|vb.net|

服務器之家 - 編程語言 - Java教程 - 如何更快樂的使用Java 8中的Lambda特性

如何更快樂的使用Java 8中的Lambda特性

2021-06-09 14:01隔葉黃鶯 Java教程

從java8出現以來lambda是最重要的特性之一,它可以讓我們用簡潔流暢的代碼完成一個功能。下面這篇文章主要給大家介紹了關于如何更快樂的使用Java 8中的Lambda特性的相關資料,需要的朋友可以參考下

前言

java 8 的 lambda 特性較之于先前的泛型加入更能鼓舞人心的,我對 lambda 的理解是它得以讓 java 以函數式思維的方式來寫代碼。而寫出的代碼是否是函數式,并不單純在包含了多少 lambda 表達式,而在思維,要神似。

實際中看過一些代碼,為了 lambda 表達式而 lambda(函數式),有一種少年不識愁滋味,為賦新詞強說愁的味道。從而致使原本一個簡單的方調用硬生生的要顯式的用類如 apply(), accept(obj) 等形式。不僅造成代碼可讀性差,且可測試性也變壞了。

為什么說的是快樂的使用 java 8 的 lambda 呢?我竊以為第一個念頭聲明 lambda 表達式為實例/類變量(像本文第一段代碼那樣),而不是方法的,一定會覺得如此使用方式很快樂的。所謂獨樂樂,不如眾樂樂;獨樂樂,眾不樂定然是更大的快樂; 更極致一些,不管什么時候必須是:我快樂,所以你也快樂。

一方面也在于 java 還沒有進化到 javascript 或  scala 那樣的水平,javascript 的函數類型變量,不一定要用 apply 或 call, 直接括號就能實現方法調用。scala 的函數類型用括號調用也會自動匹配到 apply 或 update 等方法上去。

看下面的樣本代碼

?
1
2
3
4
5
6
7
8
9
10
11
12
13
public class account {
 
 public bifunction<string, string, string> fullname = (firstname, lastname) -> {
  //some logic, i.e. logics of fullname in different countries
  return firstname + " " + lastname;
 };
 
 public string getname() {
  string firstname = "speaker";
  string lastname = "wolf";
  return fullname.apply(firstname, lastname);
 }
}

上面的 fullname lambda 表達式看起來就有點別扭,完全可以寫成一個普通方法

?
1
2
3
public string makefullname(string firstname, string lastname) {
 //return something with logics
}

那么調用起來只需要簡單的

?
1
makefullname(firstname, lastname)

那么此例中把簡單方法寫成一個 lambda 表達式來調用有什么不友好之處呢?

  • 不利于理解,lambda 表達式的類型充斥著 consumer, function, bifunction 等太寬泛的聲明
  • 參數類型與形參分離在表達式等號兩邊,不利于一一對應(右方重復一遍參數類型更不可取),真正的返回值也不明了
  • 調用時更得多余的 get(), accept(obj), apply(obj1, obj2) 那樣的方法
  • 既然有邏輯,就應該有測試,lambda 表達式雖是一個變量也不例如,測試時也不得用 apply 那樣的調用
  • lambda 表達式為變量的形式,可能會隨每一個對象實例有一單獨的拷貝。當然聲明為靜態可以避免。
  • 重構時更需大動干戈,比如前面的例子還要考慮 middlename 的情況,表達式要更動為
?
1
2
3
public trifunction<string, string, string, string> fullname = (firstname, middlename, lastname) -> {
 //.......
}

jdk 中還沒有 trifunction, 還得自己創造,不同數量的參數都得更新 lambda 表達式的類型。如果是一個普通方法重構起來就方便多了,跟多一個人多一副碗筷一樣。

 解釋上面第 #5 條,對于方法,實現代碼在 jvm 中只有一份,而 lambda 實例變量如果不捕獲外部變量的話,與方法是一樣的,例如前面的 account 為例

?
1
2
3
account account1 = new account();
account account2 = new account();
system.out.println(account1.fullname == account2.fullname); //true

但是 lambda 表達式需捕獲外部變量時,例如

?
1
2
3
4
5
6
7
8
9
private string suffix = "sir";
public bifunction<string, string, string> fullname = (firstname, lastname) -> {
 return firstname + " " + lastname + " " + suffix;
};
 
.......
account account1 = new account();
account account2 = new account();
account1.fullname == account2.fullname; //就是 false 了, 而如果 suffix 是一個靜態的變量時這個等式又是 true 了

那么新建的兩個 account 對象的 fullname 屬性就不是同一個了。因為 lambda 需要捕獲外部一個不確定的值,所以它也隨宿主實例也變。

難道不應該用 lambda 表達式變量,那倒不是,如果一個方法接受的是一個函數,如

?
1
2
3
public string getname(bifunction<string, string, string> builder) {
 return builder.apply(firstname, lastname);
}

那么是可以聲明一個 lambda 表達式變量,來傳入。不過這種情況下用方法引用還是更方便些,方法的測試總是比 lambda 表達式的測試容易。

?
1
string name = getname(this::makefullname);

個人習慣,一般需要 lambda 表達式變量時基本是聲明為局部變量,或是調用接受函數參數的方法時以內聯的方法書寫,像

?
1
2
3
4
string name = getname((firstname, lastname) -> {
 //logics
 return ......
});

對于使用方法引用方式的重構也不難,getname() 的參數類型變為 trifunction, makefullname() 方法再加一個參數就行, 調用形式仍然不變,還是

?
1
string name = getname(this::makefullname);

如果引用的方法是別人寫的也不用慌,無須總去創建一樣的方法簽名來強型上方法引用,也可以和改 lambda 實現代碼一樣的方式比改動,如下

?
1
2
3
string name = getname((firstname, lastname) ->
 makefullname(firstname, lastname) + " " + suffix
)

本人希望的是,對函數的 apply(), accept(obj) 這樣的顯式調用應該是框架設計實現的職責,對框架使用者應該透明,或者說是隱藏背后的細節,只管傳入需要的函數類型或方法引用。如果函數實現需要共享的話,寫成方法更優于一個 lambda 表達式,方法容易單獨測試。特別是用 mockito 捕獲到了一個傳入某個方法的 lambda  表達式實例時,不那么好驗證它的內部實現。

小結一下:

  • 函數式思維最關鍵應該是 data in, data out, 編程語言 lambda 特性可以促使我們達成這一目的; 但不是代碼中有了  lambda 表達就是函數式風格。
  • 其次代碼的首先是人閱讀,其次才是機器,所以它應該表達直截,明了,很強的可讀性與可測試性。
  • 具體講如何快樂使用 java 8 的 lambda 呢,僅代表本人想法,可以用內聯式,或方法引用,或局部的 lambda 表達式變量,最后才是實例/類的 lambda 表達式變量。

補充一個例子,在方法體中重復聲明完全相同的不捕獲任何外部變量的 lambda 表達式都是新的實例

?
1
2
3
consumer<string> f1 = a -> system.out.println(a);
consumer<string> f2 = a -> system.out.println(a);
system.out.println(f1 == f2); //false

以上測試在 java 8 平臺上進行的。

lambda表達式優劣

lambda表達式有優點也有缺點,優點在于大大簡化代碼行數,使代碼在一定程度上變的簡潔干凈,但是同樣的,這可能也會是一個缺點,由于省略了太多東西,代碼可讀性有可能在一定程度上會降低,這個完全取決于你使用lambda表達式的位置所設計的api是否被你的代碼的其他閱讀者所熟悉。另外的優點,也是lambda表達式比較顯眼的優點就是對外部定義的局部變量的使用更加靈活,想象一種極端情況,你的代碼中有地方需要接口回調套接口回調,有可能套了好幾層,雖然這種情況出現的概率比較低,但是一旦出現這種代碼,lambda表達式的這個優點就到了大顯身手的時機。雖然我說了,lambda表達式能用的地方非常有限,但是不得不否認,接口中只有一個抽象方法這種情況在接口回調中發生的概率絕對比接口中有多個抽象方法的概率高的多,所以,雖然使用情況很單一,但是能用到的次數卻足夠的多,如果你決定用lambda表達式替換你項目中接口回調的傳統寫法,你會發現,這樣的情況非常多。

總而言之,接口回調和lambda表達式這兩種寫法各有優劣,java 8在出現lambda表達式以后不代表原先的寫法不能再用了,所以如何選擇適合項目的寫法,全看各位開發者如何自己選擇,現在多了一種寫法可選,總歸是一件好事。

總結

以上就是這篇文章的全部內容了,希望本文的內容對大家的學習或者工作具有一定的參考學習價值,如果有疑問大家可以留言交流,謝謝大家對服務器之家的支持。

原文鏈接:https://yanbin.blog/happy-with-java8-lambda/

延伸 · 閱讀

精彩推薦
主站蜘蛛池模板: 国产精品 视频一区 二区三区 | 男人的天堂久久精品激情a 男人的天堂va | 久久免费看少妇级毛片蜜臀 | chinese军人@gay| 国内精品露脸在线视频播放 | 久久精品国产免费播放 | 久久人妻少妇嫩草AV无码 | 亚洲不卡高清免v无码屋 | 亚洲国产精品福利片在线观看 | 亚洲欧美久久久久久久久久爽网站 | 男人爱看的网站 | 晚上禁用的十大黄台视频 | а天堂中文最新版在线官网视频 | 久久香蕉国产免费天天 | 欧美日韩中文字幕一区二区高清 | 日韩激情视频在线观看 | 欧美人与牲动交xxx 欧美人妖另类性hd 欧美人人干 | 91久久99热青草国产 | 羲义嫁密着中出交尾gvg794 | 8天堂资源在线官网 | 午夜伦理 第1页 | 欧美人伦禁忌.5 | 亚洲AV中文字幕无码久久 | 无套啪啪| 大ji巴好好爽好深网站 | 99热这里只有精品久久免费 | 91夜夜人人揉人人捏人人添 | 亚洲视频一区网站 | 日本xxxxx高清免费观看 | 久久国产乱子伦精品免费不卡 | 欧美精品一区二区三区免费播放 | 免费视频一区二区 | 亚洲国产成人精品不卡青青草原 | 日本在线视频网 | 成人免费影 | 亚洲精品中文 | videos护士有奶水 | 日韩资源在线 | 九九热视频免费观看 | 久久久久嫩草影院精品 | 亚洲玖玖 |