亚洲中字慕日产2020,大陆极品少妇内射AAAAAA,无码av大香线蕉伊人久久,久久精品国产亚洲av麻豆网站

資訊專欄INFORMATION COLUMN

轉(zhuǎn) | Java8初體驗(yàn)(一)lambda表達(dá)式語(yǔ)法

Lucky_Boy / 2071人閱讀

摘要:初體驗(yàn)下面進(jìn)入本文的正題表達(dá)式。接下來(lái)展示表達(dá)式和其好基友的配合。吐槽一下方法引用表面上看起來(lái)方法引用和構(gòu)造器引用進(jìn)一步簡(jiǎn)化了表達(dá)式的書寫,但是個(gè)人覺(jué)得這方面沒(méi)有的下劃線語(yǔ)法更加通用。

感謝同事【天錦】的投稿。投稿請(qǐng)聯(lián)系 tengfei@ifeve.com

本文主要記錄自己學(xué)習(xí)Java8的歷程,方便大家一起探討和自己的備忘。因?yàn)楸救艘彩莿倓傞_(kāi)始學(xué)習(xí)Java8,所以文中肯定有錯(cuò)誤和理解偏差的地方,希望大家?guī)兔χ赋?,我?huì)持續(xù)修改和優(yōu)化。本文是該系列的第一篇,主要介紹Java8對(duì)屌絲碼農(nóng)最有吸引力的一個(gè)特性—lambda表達(dá)式。

java8的安裝

工欲善其器必先利其器,首先安裝JDK8。過(guò)程省略,大家應(yīng)該都可以自己搞定。但是有一點(diǎn)這里強(qiáng)調(diào)一下(Windows系統(tǒng)):目前我們工作的版本一般是java 6或者java 7,所以很多人安裝java8基本都是學(xué)習(xí)為主。這樣就在自己的機(jī)器上會(huì)存在多版本的JDK。而且大家一般是希望在命令行中執(zhí)行java命令是基于老版本的jdk。但是在安裝完jdk8并且沒(méi)有設(shè)置path的情況下,你如果在命令行中輸入:java -version,屏幕上會(huì)顯示是jdk 8。這是因?yàn)閖dk8安裝的時(shí)候,會(huì)默認(rèn)在C:/Windows/System32中增加java.exe,這個(gè)調(diào)用的優(yōu)先級(jí)比path設(shè)置要高。所以即使path里指定是老版本的jdk,但是執(zhí)行java命令顯示的依然是新版本的jdk。這里我們要做的就是刪除C:/Windows/System32中的java.exe文件(不要手抖!)。

Lambda初體驗(yàn)

下面進(jìn)入本文的正題–lambda表達(dá)式。首先我們看一下什么是lambda表達(dá)式。以下是維基百科上對(duì)于”Lambda expression”的解釋:

a function (or a subroutine) defined, and possibly called, without being bound to an identifier。

簡(jiǎn)單點(diǎn)說(shuō)就是:一個(gè)不用被綁定到一個(gè)標(biāo)識(shí)符上,并且可能被調(diào)用的函數(shù)。這個(gè)解釋還不夠通俗,lambda表達(dá)式可以這樣定義(不精確,自己的理解):一段帶有輸入?yún)?shù)的可執(zhí)行語(yǔ)句塊。這樣就比較好理解了吧?一例勝千言。有讀者反饋:不理解Stream的含義,所以這里先提供一個(gè)沒(méi)用stream的lambda表達(dá)式的例子。

//這里省略list的構(gòu)造
List names = ...;
Collections.sort(names, (o1, o2) -> o1.compareTo(o2));
//這里省略list的構(gòu)造
List names = ...;
Collections.sort(names, new Comparator() {
  @Override
  public int compare(String o1, String o2) {
    return o1.compareTo(o2);
  }
});

上面兩段代碼分別是:使用lambda表達(dá)式來(lái)排序和使用匿名內(nèi)部類來(lái)排序。這個(gè)例子可以很明顯的看出lambda表達(dá)式簡(jiǎn)化代碼的效果。接下來(lái)展示lambda表達(dá)式和其好基友Stream的配合。

List names = new ArrayList<>();
names.add("TaoBao");
names.add("ZhiFuBao");
List lowercaseNames = names.stream().map((String name) -> {return name.toLowerCase();}).collect(Collectors.toList());

這段代碼就是對(duì)一個(gè)字符串的列表,把其中包含的每個(gè)字符串都轉(zhuǎn)換成全小寫的字符串(熟悉Groovy和Scala的同學(xué)肯定會(huì)感覺(jué)很親切)。注意代碼第四行的map方法調(diào)用,這里map方法就是接受了一個(gè)lambda表達(dá)式(其實(shí)是一個(gè)java.util.function.Function的實(shí)例,后面會(huì)介紹)。

為什么需要Lambda表達(dá)式呢?在嘗試回答這個(gè)問(wèn)題之前,我們先看看在Java8之前,如果我們想做上面代碼的操作應(yīng)該怎么辦。

先看看普通青年的代碼:

List names = new ArrayList<>();
names.add("TaoBao");
names.add("ZhiFuBao");
List lowercaseNames = new ArrayList<>();
for (String name : names) {
  lowercaseNames.add(name.toLowerCase());
}

接下來(lái)看看文藝青年的代碼(借助Guava):

List names = new ArrayList<>();
names.add("TaoBao");
names.add("ZhiFuBao");
List lowercaseNames = FluentIterable.from(names).transform(new Function() {
  @Override
  public String apply(String name) {
    return name.toLowerCase();
  }
}).toList();

在此,我們不再討論普通青年和文藝青年的代碼風(fēng)格孰優(yōu)孰劣(有興趣的可以去google搜索“命令式編程vs聲明式編程”)。本人更加喜歡聲明式的編程風(fēng)格,所以偏好文藝青年的寫法。但是在文藝青年代碼初看起來(lái)看起來(lái)干擾信息有點(diǎn)多,F(xiàn)unction匿名類的構(gòu)造語(yǔ)法稍稍有點(diǎn)冗長(zhǎng)。所以Java8的lambda表達(dá)式給我們提供了創(chuàng)建SAM(Single Abstract Method)接口更加簡(jiǎn)單的語(yǔ)法糖。

Lambda語(yǔ)法詳解

我們?cè)诖顺橄笠幌耹ambda表達(dá)式的一般語(yǔ)法:

(Type1 param1, Type2 param2, ..., TypeN paramN) -> {
  statment1;
  statment2;
  //.............
  return statmentM;
}

從lambda表達(dá)式的一般語(yǔ)法可以看出來(lái),還是挺符合上面給出的非精確版本的定義–“一段帶有輸入?yún)?shù)的可執(zhí)行語(yǔ)句塊”。

上面的lambda表達(dá)式語(yǔ)法可以認(rèn)為是最全的版本,寫起來(lái)還是稍稍有些繁瑣。別著急,下面陸續(xù)介紹一下lambda表達(dá)式的各種簡(jiǎn)化版:

參數(shù)類型省略–絕大多數(shù)情況,編譯器都可以從上下文環(huán)境中推斷出lambda表達(dá)式的參數(shù)類型。這樣lambda表達(dá)式就變成了:

(param1,param2, ..., paramN) -> {
  statment1;
  statment2;
  //.............
  return statmentM;
}

所以我們最開(kāi)始的例子就變成了(省略了List的創(chuàng)建):

List lowercaseNames = names.stream().map((name) -> {return name.toLowerCase();}).collect(Collectors.toList());

當(dāng)lambda表達(dá)式的參數(shù)個(gè)數(shù)只有一個(gè),可以省略小括號(hào)。lambda表達(dá)式簡(jiǎn)寫為:

param1 -> {
  statment1;
  statment2;
  //.............
  return statmentM;
}

所以最開(kāi)始的例子再次簡(jiǎn)化為:

List lowercaseNames = names.stream().map(name -> {return name.toLowerCase();}).collect(Collectors.toList());

當(dāng)lambda表達(dá)式只包含一條語(yǔ)句時(shí),可以省略大括號(hào)、return和語(yǔ)句結(jié)尾的分號(hào)。lambda表達(dá)式簡(jiǎn)化為:

param1 -> statment

所以最開(kāi)始的例子再次簡(jiǎn)化為:

List lowercaseNames = names.stream().map(name -> name.toLowerCase()).collect(Collectors.toList());

使用Method Reference(具體語(yǔ)法后面介紹)

//注意,這段代碼在Idea 13.0.2中顯示有錯(cuò)誤,但是可以正常運(yùn)行
List lowercaseNames = names.stream().map(String::toLowerCase).collect(Collectors.toList());
Lambda表達(dá)式眼中的外部世界

我們前面所有的介紹,感覺(jué)上lambda表達(dá)式像一個(gè)閉關(guān)鎖國(guó)的家伙,可以訪問(wèn)給它傳遞的參數(shù),也能自己內(nèi)部定義變量。但是卻從來(lái)沒(méi)看到其訪問(wèn)它外部的變量。是不是lambda表達(dá)式不能訪問(wèn)其外部變量?我們可以這樣想:lambda表達(dá)式其實(shí)是快速創(chuàng)建SAM接口的語(yǔ)法糖,原先的SAM接口都可以訪問(wèn)接口外部變量,lambda表達(dá)式肯定也是可以(不但可以,在java8中還做了一個(gè)小小的升級(jí),后面會(huì)介紹)。

String[] array = {"a", "b", "c"};
for(Integer i : Lists.newArrayList(1,2,3)){
  Stream.of(array).map(item -> Strings.padEnd(item, i, "@")).forEach(System.out::println);
}

上面的這個(gè)例子中,map中的lambda表達(dá)式訪問(wèn)外部變量Integer i。并且可以訪問(wèn)外部變量是lambda表達(dá)式的一個(gè)重要特性,這樣我們可以看出來(lái)lambda表達(dá)式的三個(gè)重要組成部分:

輸入?yún)?shù)

可執(zhí)行語(yǔ)句

存放外部變量的空間

不過(guò)lambda表達(dá)式訪問(wèn)外部變量有一個(gè)非常重要的限制:變量不可變(只是引用不可變,而不是真正的不可變)。

String[] array = {"a", "b", "c"};
for(int i = 1; i<4; i++){
  Stream.of(array).map(item -> Strings.padEnd(item, i, "@")).forEach(System.out::println);
}

上面的代碼,會(huì)報(bào)編譯錯(cuò)誤。因?yàn)樽兞縤被lambda表達(dá)式引用,所以編譯器會(huì)隱式的把其當(dāng)成final來(lái)處理(ps:大家可以想象問(wèn)什么上一個(gè)例子不報(bào)錯(cuò),而這個(gè)報(bào)錯(cuò)。)細(xì)心的讀者肯定會(huì)發(fā)現(xiàn)不對(duì)啊,以前java的匿名內(nèi)部類在訪問(wèn)外部變量的時(shí)候,外部變量必須用final修飾。Bingo,在java8對(duì)這個(gè)限制做了優(yōu)化(前面說(shuō)的小小優(yōu)化),可以不用顯示使用final修飾,但是編譯器隱式當(dāng)成final來(lái)處理。

lambda眼中的this

在lambda中,this不是指向lambda表達(dá)式產(chǎn)生的那個(gè)SAM對(duì)象,而是聲明它的外部對(duì)象。

方法引用(Method reference)和構(gòu)造器引用(construct reference)

方法引用
前面介紹lambda表達(dá)式簡(jiǎn)化的時(shí)候,已經(jīng)看過(guò)方法引用的身影了。方法引用可以在某些條件成立的情況下,更加簡(jiǎn)化lambda表達(dá)式的聲明。方法引用語(yǔ)法格式有以下三種:

objectName::instanceMethod
ClassName::staticMethod
ClassName::instanceMethod

前兩種方式類似,等同于把lambda表達(dá)式的參數(shù)直接當(dāng)成instanceMethod|staticMethod的參數(shù)來(lái)調(diào)用。比如System.out::println等同于x->System.out.println(x);Math::max等同于(x, y)->Math.max(x,y)。

最后一種方式,等同于把lambda表達(dá)式的第一個(gè)參數(shù)當(dāng)成instanceMethod的目標(biāo)對(duì)象,其他剩余參數(shù)當(dāng)成該方法的參數(shù)。比如String::toLowerCase等同于x->x.toLowerCase()。

構(gòu)造器引用

構(gòu)造器引用語(yǔ)法如下:ClassName::new,把lambda表達(dá)式的參數(shù)當(dāng)成ClassName構(gòu)造器的參數(shù) 。例如BigDecimal::new等同于x->new BigDecimal(x)。

吐槽一下方法引用

表面上看起來(lái)方法引用和構(gòu)造器引用進(jìn)一步簡(jiǎn)化了lambda表達(dá)式的書寫,但是個(gè)人覺(jué)得這方面沒(méi)有Scala的下劃線語(yǔ)法更加通用。比較才能看出,翠花,上代碼!

List names = new ArrayList<>();
names.add("TaoBao");
names.add("ZhiFuBao");
names.stream().map(name -> name.charAt(0)).collect(Collectors.toList());

上面的這段代碼就是給定一個(gè)String類型的List,獲取每個(gè)String的首字母,并將其組合成新的List。這段代碼就沒(méi)辦法使用方法引用來(lái)簡(jiǎn)化。接下來(lái),我們簡(jiǎn)單對(duì)比一下Scala的下劃線語(yǔ)法(不必太糾結(jié)Scala的語(yǔ)法,這里只是做個(gè)對(duì)比):

//省略List的初始化
List[String] names = ....
names.map(_.charAt(0))

在Scala中基本不用寫lambda表達(dá)式的參數(shù)聲明。

引用文檔
《Java SE 8 for the Really Impatient》
Java 8 Tutorial
Java 8 API doc
原創(chuàng)文章,轉(zhuǎn)載請(qǐng)注明: 轉(zhuǎn)載自并發(fā)編程網(wǎng) – ifeve.com本文鏈接地址: Java8初體驗(yàn)(一)lambda表達(dá)式語(yǔ)法

文章版權(quán)歸作者所有,未經(jīng)允許請(qǐng)勿轉(zhuǎn)載,若此文章存在違規(guī)行為,您可以聯(lián)系管理員刪除。

轉(zhuǎn)載請(qǐng)注明本文地址:http://www.ezyhdfw.cn/yun/65131.html

相關(guān)文章

  • 轉(zhuǎn) | Java8體驗(yàn)(二)Stream語(yǔ)法詳解

    摘要:第一個(gè)函數(shù)生成一個(gè)新的實(shí)例第二個(gè)函數(shù)接受兩個(gè)參數(shù),第一個(gè)是前面生成的對(duì)象,二個(gè)是中包含的元素,函數(shù)體就是把中的元素加入對(duì)象中。 感謝同事【天錦】的投稿。投稿請(qǐng)聯(lián)系 tengfei@ifeve.com 上篇文章[Java8初體驗(yàn)(一)lambda表達(dá)式語(yǔ)法]()比較詳細(xì)的介紹了lambda表達(dá)式的方方面面,細(xì)心的讀者會(huì)發(fā)現(xiàn)那篇文章的例子中有很多Stream的例子。這些Stream的例子可...

    taoszu 評(píng)論0 收藏0
  • Java8-8-方法引用詳解

    摘要:實(shí)際上方法引用是表達(dá)式的一種語(yǔ)法糖。小結(jié)本篇全面介紹了方法引用的四種使用方式,且每種方式都有對(duì)應(yīng)一個(gè)示例來(lái)幫助大家理解。 上一篇我們?cè)敿?xì)介紹了Optional類用來(lái)避免空指針問(wèn)題,本篇我們?nèi)媪私庖幌翵ava8中的方法引用特性。方法引用是lambda表達(dá)式的一種特殊形式,如果正好有某個(gè)方法滿足一個(gè)lambda表達(dá)式的形式,那就可以將這個(gè)lambda表達(dá)式用方法引用的方式表示,但是如果這...

    劉東 評(píng)論0 收藏0
  • Java8新特性第1章(Lambda達(dá)式)

    摘要:一表達(dá)式匿名內(nèi)部類最大的問(wèn)題在于其冗余的語(yǔ)法,比如前面的中五行代碼僅有一行是在執(zhí)行任務(wù)??偨Y(jié)基于詞法作用域的理念,表達(dá)式不可以掩蓋任何其所在上下文的局部變量。 轉(zhuǎn)載請(qǐng)注明出處:https://zhuanlan.zhihu.com/p/20540175 在介紹Lambda表達(dá)式之前,我們先來(lái)看只有單個(gè)方法的Interface(通常我們稱之為回調(diào)接口): public interface...

    ningwang 評(píng)論0 收藏0
  • 樂(lè)字節(jié)Java8核心特性實(shí)戰(zhàn)之方法引用

    摘要:大家好,我是樂(lè)字節(jié)的小樂(lè),上一次我們說(shuō)到了核心特性之函數(shù)式接口,接下來(lái)我們繼續(xù)了解又一核心特性方法引用。方法引用是一種更簡(jiǎn)潔易懂的表達(dá)式。感謝光臨閱讀小樂(lè)的,敬請(qǐng)關(guān)注樂(lè)字節(jié)后續(xù)將繼續(xù)講述等前沿知識(shí)技術(shù)。 大家好,我是樂(lè)字節(jié)的小樂(lè),上一次我們說(shuō)到了Java8核心特性之函數(shù)式接口,接下來(lái)我們繼續(xù)了解Java8又一核心特性——方法引用。 showImg(https://segmentfaul...

    lakeside 評(píng)論0 收藏0
  • Java8 lambda支持

    摘要:函數(shù)式編程說(shuō)前,先理解下什么是函數(shù)式編程,如果你是個(gè)純程序員,而且之前一直是沒(méi)有使用過(guò),可能還沒(méi)有使用過(guò)這種編程方式。表達(dá)式可以表示閉包注意和數(shù)學(xué)傳統(tǒng)意義上的不同。意思就是說(shuō),只要是接口類型,我們都可以傳入表達(dá)式。在包下定義了各種函數(shù)接口 函數(shù)式編程 說(shuō)lambdas前,先理解下什么是函數(shù)式編程,如果你是個(gè)純Java程序員,而且之前一直是沒(méi)有使用過(guò)Java8,可能還沒(méi)有使用過(guò)這種編程方...

    Betta 評(píng)論0 收藏0

發(fā)表評(píng)論

0條評(píng)論

最新活動(dòng)
閱讀需要支付1元查看
<