欧美bbbwbbbw肥妇,免费乱码人妻系列日韩,一级黄片

如何更快樂(lè)的使用Java 8中的Lambda特性

 更新時(shí)間:2018年11月01日 11:34:42   作者:隔葉黃鶯  
從java8出現(xiàn)以來(lái)lambda是最重要的特性之一,它可以讓我們用簡(jiǎn)潔流暢的代碼完成一個(gè)功能。下面這篇文章主要給大家介紹了關(guān)于如何更快樂(lè)的使用Java 8中的Lambda特性的相關(guān)資料,需要的朋友可以參考下

前言

Java 8 的 Lambda 特性較之于先前的泛型加入更能鼓舞人心的,我對(duì) Lambda 的理解是它得以讓 Java 以函數(shù)式思維的方式來(lái)寫代碼。而寫出的代碼是否是函數(shù)式,并不單純?cè)诎硕嗌?Lambda 表達(dá)式,而在思維,要神似。

實(shí)際中看過(guò)一些代碼,為了 Lambda 表達(dá)式而 Lambda(函數(shù)式),有一種少年不識(shí)愁滋味,為賦新詞強(qiáng)說(shuō)愁的味道。從而致使原本一個(gè)簡(jiǎn)單的方調(diào)用硬生生的要顯式的用類如 apply(), accept(obj) 等形式。不僅造成代碼可讀性差,且可測(cè)試性也變壞了。

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

一方面也在于 Java 還沒(méi)有進(jìn)化到 JavaScript 或  Scala 那樣的水平,JavaScript 的函數(shù)類型變量,不一定要用 apply 或 call, 直接括號(hào)就能實(shí)現(xiàn)方法調(diào)用。Scala 的函數(shù)類型用括號(hào)調(diào)用也會(huì)自動(dòng)匹配到 apply 或 update 等方法上去。

看下面的樣本代碼

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 表達(dá)式看起來(lái)就有點(diǎn)別扭,完全可以寫成一個(gè)普通方法

 public String makeFullName(String firstName, String lastName) {
  //return something with logics
 }

那么調(diào)用起來(lái)只需要簡(jiǎn)單的

makeFullName(firstName, lastName)

那么此例中把簡(jiǎn)單方法寫成一個(gè) Lambda 表達(dá)式來(lái)調(diào)用有什么不友好之處呢?

  • 不利于理解,Lambda 表達(dá)式的類型充斥著 Consumer, Function, BiFunction 等太寬泛的聲明
  • 參數(shù)類型與形參分離在表達(dá)式等號(hào)兩邊,不利于一一對(duì)應(yīng)(右方重復(fù)一遍參數(shù)類型更不可取),真正的返回值也不明了
  • 調(diào)用時(shí)更得多余的 get(), accept(obj), apply(obj1, obj2) 那樣的方法
  • 既然有邏輯,就應(yīng)該有測(cè)試,Lambda 表達(dá)式雖是一個(gè)變量也不例如,測(cè)試時(shí)也不得用 apply 那樣的調(diào)用
  • Lambda 表達(dá)式為變量的形式,可能會(huì)隨每一個(gè)對(duì)象實(shí)例有一單獨(dú)的拷貝。當(dāng)然聲明為靜態(tài)可以避免。
  • 重構(gòu)時(shí)更需大動(dòng)干戈,比如前面的例子還要考慮 middleName 的情況,表達(dá)式要更動(dòng)為
public TriFunction<String, String, String, String> fullName = (firstName, middleName, lastName) -> {
 //.......
}

JDK 中還沒(méi)有 TriFunction, 還得自己創(chuàng)造,不同數(shù)量的參數(shù)都得更新 Lambda 表達(dá)式的類型。如果是一個(gè)普通方法重構(gòu)起來(lái)就方便多了,跟多一個(gè)人多一副碗筷一樣。

 解釋上面第 #5 條,對(duì)于方法,實(shí)現(xiàn)代碼在 JVM 中只有一份,而 Lambda 實(shí)例變量如果不捕獲外部變量的話,與方法是一樣的,例如前面的 Account 為例

Account account1 = new Account();
Account account2 = new Account();
System.out.println(account1.fullName == account2.fullName); //true

但是 Lambda 表達(dá)式需捕獲外部變量時(shí),例如

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 是一個(gè)靜態(tài)的變量時(shí)這個(gè)等式又是 true 了

那么新建的兩個(gè) Account 對(duì)象的 fullName 屬性就不是同一個(gè)了。因?yàn)?Lambda 需要捕獲外部一個(gè)不確定的值,所以它也隨宿主實(shí)例也變。

難道不應(yīng)該用 Lambda 表達(dá)式變量,那倒不是,如果一個(gè)方法接受的是一個(gè)函數(shù),如

public String getName(BiFunction<String, String, String> builder) {
 return builder.apply(firstName, lastName);
}

那么是可以聲明一個(gè) Lambda 表達(dá)式變量,來(lái)傳入。不過(guò)這種情況下用方法引用還是更方便些,方法的測(cè)試總是比 Lambda 表達(dá)式的測(cè)試容易。

String name = getName(this::makeFullName);

個(gè)人習(xí)慣,一般需要 Lambda 表達(dá)式變量時(shí)基本是聲明為局部變量,或是調(diào)用接受函數(shù)參數(shù)的方法時(shí)以內(nèi)聯(lián)的方法書寫,像

String name = getName((firstName, lastName) -> {
 //logics
 return ......
});

對(duì)于使用方法引用方式的重構(gòu)也不難,getName() 的參數(shù)類型變?yōu)?TriFunction, makeFullName() 方法再加一個(gè)參數(shù)就行, 調(diào)用形式仍然不變,還是

String name = getName(this::makeFullName);

如果引用的方法是別人寫的也不用慌,無(wú)須總?cè)?chuàng)建一樣的方法簽名來(lái)強(qiáng)型上方法引用,也可以和改 Lambda 實(shí)現(xiàn)代碼一樣的方式比改動(dòng),如下

String name = getName((firstName, lastName) -> 
 makeFullName(firstName, lastName) + " " + suffix
)

本人希望的是,對(duì)函數(shù)的 apply(), accept(obj) 這樣的顯式調(diào)用應(yīng)該是框架設(shè)計(jì)實(shí)現(xiàn)的職責(zé),對(duì)框架使用者應(yīng)該透明,或者說(shuō)是隱藏背后的細(xì)節(jié),只管傳入需要的函數(shù)類型或方法引用。如果函數(shù)實(shí)現(xiàn)需要共享的話,寫成方法更優(yōu)于一個(gè) Lambda 表達(dá)式,方法容易單獨(dú)測(cè)試。特別是用 Mockito 捕獲到了一個(gè)傳入某個(gè)方法的 Lambda  表達(dá)式實(shí)例時(shí),不那么好驗(yàn)證它的內(nèi)部實(shí)現(xiàn)。

小結(jié)一下:

  • 函數(shù)式思維最關(guān)鍵應(yīng)該是 Data In, Data Out, 編程語(yǔ)言 Lambda 特性可以促使我們達(dá)成這一目的; 但不是代碼中有了  Lambda 表達(dá)就是函數(shù)式風(fēng)格。
  • 其次代碼的首先是人閱讀,其次才是機(jī)器,所以它應(yīng)該表達(dá)直截,明了,很強(qiáng)的可讀性與可測(cè)試性。
  • 具體講如何快樂(lè)使用 Java 8 的 Lambda 呢,僅代表本人想法,可以用內(nèi)聯(lián)式,或方法引用,或局部的 Lambda 表達(dá)式變量,最后才是實(shí)例/類的 Lambda 表達(dá)式變量。

補(bǔ)充一個(gè)例子,在方法體中重復(fù)聲明完全相同的不捕獲任何外部變量的 Lambda 表達(dá)式都是新的實(shí)例

 Consumer<String> f1 = a -> System.out.println(a);
 Consumer<String> f2 = a -> System.out.println(a);
 System.out.println(f1 == f2); //false

以上測(cè)試在 Java 8 平臺(tái)上進(jìn)行的。

lambda表達(dá)式優(yōu)劣

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

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

總結(jié)

以上就是這篇文章的全部?jī)?nèi)容了,希望本文的內(nèi)容對(duì)大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價(jià)值,如果有疑問(wèn)大家可以留言交流,謝謝大家對(duì)腳本之家的支持。

相關(guān)文章

  • MyBatis-Flex實(shí)現(xiàn)分頁(yè)查詢的示例代碼

    MyBatis-Flex實(shí)現(xiàn)分頁(yè)查詢的示例代碼

    在MyBatis-Flex中實(shí)現(xiàn)分頁(yè)查詢時(shí),需要注意維護(hù)一個(gè)獲取數(shù)據(jù)庫(kù)總數(shù)的方法,詳細(xì)介紹了UserService、UserServiceImpl類以及Mapper.xml配置,感興趣的可以了解一下
    2024-10-10
  • Spring Boot 快速入門指南

    Spring Boot 快速入門指南

    Spring 框架是非常著名的 Java 開源框架,歷經(jīng)十多年的發(fā)展,整個(gè)生態(tài)系統(tǒng)已經(jīng)非常完善甚至是繁雜,Spring Boot 正是為了解決這個(gè)問(wèn)題而開發(fā)的,為 Spring 平臺(tái)和第三方庫(kù)提供了開箱即用的設(shè)置,只需要很少的配置就可以開始一個(gè) Spring 項(xiàng)目
    2017-03-03
  • Spring注解之@PropertySource詳解

    Spring注解之@PropertySource詳解

    這篇文章主要介紹了Spring注解之@PropertySource詳解,@PropertySource注解用于指定資源文件讀取的位置,它不僅能讀取properties文件,也能讀取xml文件,并且通過(guò)YAML解析器,配合自定義PropertySourceFactory實(shí)現(xiàn)解析YAML文件,需要的朋友可以參考下
    2023-11-11
  • SpringBoot集成Mybatis并測(cè)試

    SpringBoot集成Mybatis并測(cè)試

    這篇文章主要介紹了SpringBoot集成Mybatis并測(cè)試,本文通過(guò)實(shí)例代碼給大家介紹的非常詳細(xì),對(duì)大家的學(xué)習(xí)或工作具有一定的參考借鑒價(jià)值,需要的朋友可以參考下
    2022-02-02
  • Spring DevTools的介紹

    Spring DevTools的介紹

    今天小編就為大家分享一篇關(guān)于Spring DevTools的介紹,小編覺(jué)得內(nèi)容挺不錯(cuò)的,現(xiàn)在分享給大家,具有很好的參考價(jià)值,需要的朋友一起跟隨小編來(lái)看看吧
    2018-12-12
  • java object 之clone方法全面解析

    java object 之clone方法全面解析

    下面小編就為大家?guī)?lái)一篇java object 之clone方法全面解析。小編覺(jué)得挺不錯(cuò)的,現(xiàn)在就分享給大家,也給大家做個(gè)參考。一起跟隨小編過(guò)來(lái)看看吧
    2016-06-06
  • java多態(tài)機(jī)制原理特點(diǎn)詳解

    java多態(tài)機(jī)制原理特點(diǎn)詳解

    在本篇文章里小編給大家分享的是關(guān)于java多態(tài)機(jī)制原理特點(diǎn)詳解,有需要的朋友們可以跟著學(xué)習(xí)下。
    2020-02-02
  • 關(guān)于Spring?Ioc和DI注解的問(wèn)題

    關(guān)于Spring?Ioc和DI注解的問(wèn)題

    這篇文章主要介紹了Spring?Ioc和DI注解,本文給大家介紹的非常詳細(xì),對(duì)大家的學(xué)習(xí)或工作具有一定的參考借鑒價(jià)值,需要的朋友可以參考下
    2022-03-03
  • Java 中 Reference用法詳解

    Java 中 Reference用法詳解

    這篇文章主要介紹了Java 中 Reference用法詳解的相關(guān)資料,需要的朋友可以參考下
    2017-03-03
  • Kotlin常用函數(shù)let,with,run,apply用法與區(qū)別案例詳解

    Kotlin常用函數(shù)let,with,run,apply用法與區(qū)別案例詳解

    這篇文章主要介紹了Kotlin常用函數(shù)let,with,run,apply用法與區(qū)別案例詳解,本篇文章通過(guò)簡(jiǎn)要的案例,講解了該項(xiàng)技術(shù)的了解與使用,以下就是詳細(xì)內(nèi)容,需要的朋友可以參考下
    2021-09-09

最新評(píng)論