中文字幕精品亚洲无线码二区,国产黄a三级三级三级看三级,亚洲七七久久桃花影院,丰满少妇被猛烈进入,国产小视频在线观看网站

Java8 lambda表達式(shi)10個示例

例1、用lambda表達式實現Runnable

我(wo)開始使用Java 8時,首(shou)先做(zuo)的(de)就是使用lambda表達式替換匿(ni)名(ming)類(lei),而實現Runnable接口是匿(ni)名(ming)類(lei)的(de)最好示例。看(kan)一(yi)下Java 8之前的(de)runnable實現方法,需(xu)要(yao)4行代(dai)碼(ma),而使用lambda表達式只需(xu)要(yao)一(yi)行代(dai)碼(ma)。我(wo)們在這里做(zuo)了(le)什么呢?那就是用() -> {}代(dai)碼(ma)塊替代(dai)了(le)整個。

// Java 8之(zhi)前:
new Thread(new Runnable() {
    @Override
    public void run() {
    System.out.println("Before Java8, too much code for too little to do");
    }
}).start();

//Java 8方式:
new Thread( () -> System.out.println("In Java8, Lambda expression rocks !!") ).start();

輸出:

too much code, for too little to do
Lambda expression rocks !!

這(zhe)個例子向我們展示了Java 8 lambda表達(da)式的(de)語法。你可以使用lambda寫出如下代碼:

(params) -> expression
(params) -> statement
(params) -> { statements }

例(li)如,如果你的(de)(de)方法不對參數進行修改、重寫(xie),只是在控(kong)制臺打印點東西的(de)(de)話,那么可(ke)以(yi)這(zhe)樣寫(xie):

() -> System.out.println("Hello Lambda Expressions");

如果(guo)你的方法接收兩個參數,那么可以寫(xie)成如下(xia)這樣:

(int even, int odd) -> even + odd

順便(bian)提一句,通常都會(hui)把lambda表達(da)式內部變量(liang)的(de)名(ming)字起(qi)得(de)短一些(xie)。這樣能使代碼(ma)更簡短,放在同一行。所以,在上(shang)述(shu)代碼(ma)中,變量(liang)名(ming)選用a、b或者x、y會(hui)比even、odd要(yao)好。

例2、使用Java 8 lambda表達式進行事件處理

如(ru)果你(ni)用過Swing API編程,你(ni)就會記得怎樣(yang)寫事(shi)(shi)件監(jian)(jian)聽(ting)代(dai)碼(ma)。這(zhe)又是一個(ge)舊版本簡(jian)單匿名類的(de)經典(dian)用例,但(dan)現在可以不這(zhe)樣(yang)了。你(ni)可以用lambda表達式寫出更好(hao)的(de)事(shi)(shi)件監(jian)(jian)聽(ting)代(dai)碼(ma),如(ru)下(xia)所示(shi):

// Java 8之(zhi)前:
JButton show =  new JButton("Show");
show.addActionListener(new ActionListener() {
    @Override
    public void actionPerformed(ActionEvent e) {
    System.out.println("Event handling without lambda expression is boring");
    }
});

// Java 8方式:
show.addActionListener((e) -> {
    System.out.println("Light, Camera, Action !! Lambda expressions Rocks");
});

Java開發者經常使用(yong)匿名類(lei)(lei)的(de)另(ling)一(yi)個(ge)(ge)地方是為 Collections.sort() 定制(zhi) 。在(zai)Java 8中,你可(ke)以用(yong)更可(ke)讀的(de)lambda表(biao)達(da)式換掉丑陋的(de)匿名類(lei)(lei)。我把這個(ge)(ge)留做練習,應該(gai)不難,可(ke)以按照我在(zai)使用(yong)lambda表(biao)達(da)式實現  和 ActionListener 的(de)過程中的(de)套路來做。

例3、使用lambda表達式對列表進行迭代

如(ru)果(guo)你(ni)使(shi)(shi)過(guo)幾(ji)年Java,你(ni)就(jiu)知道針對(dui)集合類(lei),最常見的操(cao)作就(jiu)是進(jin)(jin)行迭代(dai),并(bing)將(jiang)(jiang)(jiang)業務邏輯應(ying)用于各個元素,例(li)如(ru)處理訂單、交易和(he)(he)事件(jian)的列(lie)(lie)表(biao)(biao)。由于Java是命令式語言,Java 8之(zhi)前的所有循(xun)環代(dai)碼(ma)都是順序(xu)的,即可(ke)以(yi)對(dui)其元素進(jin)(jin)行并(bing)行化(hua)處理。如(ru)果(guo)你(ni)想(xiang)做(zuo)并(bing)行過(guo)濾,就(jiu)需要自己寫代(dai)碼(ma),這(zhe)并(bing)不(bu)是那(nei)么(me)容(rong)易。通過(guo)引入(ru)lambda表(biao)(biao)達式和(he)(he)默認方法(fa),將(jiang)(jiang)(jiang)做(zuo)什么(me)和(he)(he)怎么(me)做(zuo)的問題(ti)分開了,這(zhe)意味著Java集合現在(zai)知道怎樣做(zuo)迭代(dai),并(bing)可(ke)以(yi)在(zai)API層面對(dui)集合元素進(jin)(jin)行并(bing)行處理。下面的例(li)子里,我將(jiang)(jiang)(jiang)介紹如(ru)何在(zai)或不(bu)使(shi)(shi)用lambda表(biao)(biao)達式的情況下迭代(dai)列(lie)(lie)表(biao)(biao)。你(ni)可(ke)以(yi)看到(dao)列(lie)(lie)表(biao)(biao)現在(zai)有了一個 forEach()  方法(fa),它可(ke)以(yi)迭代(dai)所有對(dui)象,并(bing)將(jiang)(jiang)(jiang)你(ni)的lambda代(dai)碼(ma)應(ying)用在(zai)其中(zhong)。

// Java 8之前:
List features = Arrays.asList("Lambdas", "Default Method", "Stream API", "Date and Time API");
for (String feature : features) {
    System.out.println(feature);
}

// Java 8之后:
List features = Arrays.asList("Lambdas", "Default Method", "Stream API", "Date and Time API");
features.forEach(n -> System.out.println(n));
 
// 使用Java 8的方法引用更方便,方法引用由::雙(shuang)冒號操作符標示,
// 看起來像C++的作用域解析運算符
features.forEach(System.out::println);

輸出:

Lambdas
Default Method
Stream API
Date and Time API

的最后(hou)一個例子展示了如何(he)在(zai)(zai)Java 8中(zhong)使(shi)用(yong)方(fang)法引(yin)用(yong)(method reference)。你可以(yi)看到(dao)C++里面的雙(shuang)冒(mao)號、范圍解析(xi)操作符現在(zai)(zai)在(zai)(zai)Java 8中(zhong)用(yong)來表示方(fang)法引(yin)用(yong)。

例4、使用lambda表達式和函數式接口Predicate

除了在語(yu)言(yan)層面支持(chi)函數(shu)(shu)式編(bian)程(cheng)風格,Java 8也(ye)添(tian)加了一(yi)個(ge)包(bao),叫做 java.util.function。它(ta)包(bao)含了很(hen)多類,用(yong)來支持(chi)Java的函數(shu)(shu)式編(bian)程(cheng)。其中一(yi)個(ge)便(bian)是Predicate,使用(yong) java.util.function.Predicate 函數(shu)(shu)式接(jie)(jie)口以及lambda表達式,可以向API方法添(tian)加邏輯,用(yong)更少的代(dai)碼支持(chi)更多的動態行為。下面是Java 8 Predicate 的例(li)子,展示(shi)了過濾集合數(shu)(shu)據的多種常用(yong)方法。Predicate接(jie)(jie)口非(fei)常適(shi)用(yong)于做過濾。

public static void main(args[]){
    List languages = Arrays.asList("Java", "Scala", "C++", "Haskell", "Lisp");
 
    System.out.println("Languages which starts with J :");
    filter(languages, (str)->str.startsWith("J"));
 
    System.out.println("Languages which ends with a ");
    filter(languages, (str)->str.endsWith("a"));
 
    System.out.println("Print all languages :");
    filter(languages, (str)->true);
 
    System.out.println("Print no language : ");
    filter(languages, (str)->false);
 
    System.out.println("Print language whose length greater than 4:");
    filter(languages, (str)->str.length() > 4);
}
 
public static void filter(List names, Predicate condition) {
    for(String name: names)  {
        if(condition.test(name)) {
            System.out.println(name + " ");
        }
    }
}

輸出:

Languages which starts with J :
Java
Languages which ends with a
Java
Scala
Print all languages :
Java
Scala
C++
Haskell
Lisp
Print no language :
Print language whose length greater than 4:
Scala
Haskell
// 更(geng)好的辦法
public static void filter(List names, Predicate condition) {
    names.stream().filter((name) -> (condition.test(name))).forEach((name) -> {
        System.out.println(name + " ");
    });
}

可(ke)以看(kan)到(dao),Stream API的(de)(de)過濾方法也(ye)(ye)接受一個(ge)(ge)Predicate,這(zhe)意味著可(ke)以將我們定(ding)制的(de)(de) filter() 方法替換(huan)成寫在里面的(de)(de)內聯(lian)代(dai)碼(ma),這(zhe)就(jiu)是lambda表達式(shi)的(de)(de)魔力。另外,Predicate接口也(ye)(ye)允(yun)許進行(xing)多重條件的(de)(de)測(ce)試,下個(ge)(ge)例子將要(yao)講到(dao)。

例5、如何在lambda表達式中加入Predicate

上個(ge)例(li)(li)子說到,java.util.function.Predicate 允許將兩個(ge)或更多的(de)(de) Predicate 合成一個(ge)。它(ta)提供類(lei)似于邏輯(ji)操作符AND和OR的(de)(de)方(fang)(fang)法,名字(zi)叫做and()、or()和xor(),用于將傳(chuan)入 filter() 方(fang)(fang)法的(de)(de)條件合并(bing)起來。例(li)(li)如,要得到所有以J開始,長(chang)度為四個(ge)字(zi)母(mu)的(de)(de)語言,可以定義兩個(ge)獨立的(de)(de) Predicate 示(shi)例(li)(li)分別表示(shi)每(mei)一個(ge)條件,然后用 Predicate.and() 方(fang)(fang)法將它(ta)們(men)合并(bing)起來,如下所示(shi):

// 甚至可以用and()、or()和xor()邏(luo)輯函(han)數來合并(bing)Predicate,
// 例(li)如要(yao)找到所有(you)以J開(kai)始(shi),長度為四個字母的名字,你可以合并(bing)兩個Predicate并(bing)傳(chuan)入
Predicate<String> startsWithJ = (n) -> n.startsWith("J");
Predicate<String> fourLetterLong = (n) -> n.length() == 4;
names.stream()
    .filter(startsWithJ.and(fourLetterLong))
    .forEach((n) -> System.out.print("nName, which starts with 'J' and four letter long is : " + n));

類似(si)地,也(ye)可以(yi)使(shi)用 or() 和 xor() 方(fang)法。本例(li)著重介紹了如下要(yao)(yao)點:可按需要(yao)(yao)將 Predicate 作為單獨(du)條件然后將其合并起來使(shi)用。簡(jian)而言之,你可以(yi)以(yi)傳(chuan)統(tong)Java命令方(fang)式(shi)使(shi)用 Predicate 接口(kou),也(ye)可以(yi)充分(fen)利用lambda表達式(shi)達到事半功(gong)倍的效果。

例6、Java 8中使用lambda表達式的Map和Reduce示例

本(ben)例(li)介紹最廣為人知的(de)函數式(shi)編程(cheng)概念map。它允許你將(jiang)(jiang)對象進行轉換。例(li)如(ru)在(zai)本(ben)例(li)中(zhong),我們將(jiang)(jiang) costBeforeTax 列表(biao)的(de)每(mei)個(ge)(ge)元素(su)轉換成為稅后(hou)的(de)值。我們將(jiang)(jiang) x -> x*x lambda表(biao)達式(shi)傳到 map() 方(fang)(fang)法(fa),后(hou)者(zhe)將(jiang)(jiang)其應用(yong)到流(liu)中(zhong)的(de)每(mei)一(yi)個(ge)(ge)元素(su)。然后(hou)用(yong) forEach() 將(jiang)(jiang)列表(biao)元素(su)打(da)印出來(lai)。使用(yong)流(liu)API的(de)收集器(qi)類,可(ke)以得到所有含稅的(de)開銷。有 toList() 這樣的(de)方(fang)(fang)法(fa)將(jiang)(jiang) map 或任何其他(ta)操作(zuo)的(de)結果合并起(qi)來(lai)。由于收集器(qi)在(zai)流(liu)上(shang)做(zuo)終端操作(zuo),因此之后(hou)便不(bu)能(neng)重用(yong)流(liu)了。你甚至可(ke)以用(yong)流(liu)API的(de) reduce() 方(fang)(fang)法(fa)將(jiang)(jiang)所有數字合成一(yi)個(ge)(ge),下一(yi)個(ge)(ge)例(li)子將(jiang)(jiang)會(hui)講到。

// 不使用lambda表(biao)達式為(wei)每個訂單加上12%的稅
List costBeforeTax = Arrays.asList(100, 200, 300, 400, 500);
for (Integer cost : costBeforeTax) {
    double price = cost + .12*cost;
    System.out.println(price);
}
 
// 使(shi)用lambda表(biao)達式
List costBeforeTax = Arrays.asList(100, 200, 300, 400, 500);
costBeforeTax.stream().map((cost) -> cost + .12*cost).forEach(System.out::println);

輸出:

112.0
224.0
336.0
448.0
560.0
112.0
224.0
336.0
448.0
560.0

例6.2、Java 8中使用lambda表達式的Map和Reduce示例

在上個(ge)(ge)例(li)子中,可(ke)(ke)以(yi)看到map將集合類(lei)(lei)(lei)(例(li)如列表(biao))元(yuan)素進行(xing)轉(zhuan)換的(de)(de)。還有(you)(you)一(yi)個(ge)(ge) reduce() 函數(shu)可(ke)(ke)以(yi)將所有(you)(you)值合并成一(yi)個(ge)(ge)。Map和Reduce操(cao)(cao)作是函數(shu)式(shi)編程的(de)(de)核(he)心操(cao)(cao)作,因為其功(gong)能,reduce 又被稱(cheng)為折疊(die)操(cao)(cao)作。另外(wai),reduce 并不是一(yi)個(ge)(ge)新的(de)(de)操(cao)(cao)作,你有(you)(you)可(ke)(ke)能已經在使(shi)用(yong)(yong)它。SQL中類(lei)(lei)(lei)似 sum()、avg() 或者 count() 的(de)(de)聚集函數(shu),實際上就(jiu)是 reduce 操(cao)(cao)作,因為它們(men)接(jie)收(shou)多個(ge)(ge)值并返回一(yi)個(ge)(ge)值。流API定義的(de)(de) reduceh() 函數(shu)可(ke)(ke)以(yi)接(jie)受lambda表(biao)達式(shi),并對所有(you)(you)值進行(xing)合并。IntStream這樣的(de)(de)類(lei)(lei)(lei)有(you)(you)類(lei)(lei)(lei)似 average()、count()、sum() 的(de)(de)內建方(fang)法來做 reduce 操(cao)(cao)作,也有(you)(you)mapToLong()、mapToDouble() 方(fang)法來做轉(zhuan)換。這并不會限(xian)制你,你可(ke)(ke)以(yi)用(yong)(yong)內建方(fang)法,也可(ke)(ke)以(yi)自己定義。在這個(ge)(ge)Java 8的(de)(de)Map Reduce示例(li)里,我們(men)首先對所有(you)(you)價(jia)格應用(yong)(yong) 12% 的(de)(de)VAT,然后用(yong)(yong) reduce() 方(fang)法計算總和。

// 為每個訂單(dan)加上12%的稅(shui)
// 老(lao)方法:
List costBeforeTax = Arrays.asList(100, 200, 300, 400, 500);
double total = 0;
for (Integer cost : costBeforeTax) {
    double price = cost + .12*cost;
    total = total + price;
}
System.out.println("Total : " + total);
 
// 新方法:
List costBeforeTax = Arrays.asList(100, 200, 300, 400, 500);
double bill = costBeforeTax.stream().map((cost) -> cost + .12*cost).reduce((sum, cost) -> sum + cost).get();
System.out.println("Total : " + bill);

輸出:

Total : 1680.0
Total : 1680.0

例7、通過過濾創建一個String列表

過(guo)濾是Java開發者在大(da)(da)規(gui)模集(ji)合上的一(yi)個(ge)(ge)常(chang)用操作(zuo),而現(xian)在使用lambda表(biao)達(da)(da)式和流(liu)API過(guo)濾大(da)(da)規(gui)模數據集(ji)合是驚人的簡單。流(liu)提(ti)供了一(yi)個(ge)(ge) filter() 方法,接受(shou)一(yi)個(ge)(ge) Predicate 對象,即可以(yi)傳(chuan)入一(yi)個(ge)(ge)lambda表(biao)達(da)(da)式作(zuo)為過(guo)濾邏輯。下面的例子是用lambda表(biao)達(da)(da)式過(guo)濾Java集(ji)合,將幫助(zhu)理解(jie)。

// 創建(jian)一(yi)個字(zi)符串列表,每個字(zi)符串長度(du)大于2
List<String> filtered = strList.stream().filter(x -> x.length()> 2).collect(Collectors.toList());
System.out.printf("Original List : %s, filtered list : %s %n", strList, filtered);

輸出:

Original List : [abc, , bcd, , defg, jk], filtered list : [abc, bcd, defg]

另外,關于 filter() 方法有個(ge)常見誤(wu)解。在(zai)現實生活(huo)中,做(zuo)過濾(lv)的(de)時候,通常會(hui)丟棄部分,但使用(yong)filter()方法則是獲(huo)得一(yi)個(ge)新的(de)列表,且其(qi)每個(ge)元素符(fu)合(he)過濾(lv)原則。

例8、對列表的每個元素應用函數

我們(men)通常需要(yao)對列(lie)表的(de)每(mei)個(ge)(ge)(ge)元素(su)使用某(mou)(mou)個(ge)(ge)(ge)函數,例(li)如逐一乘以(yi)某(mou)(mou)個(ge)(ge)(ge)數、除以(yi)某(mou)(mou)個(ge)(ge)(ge)數或者做(zuo)其它操作。這些操作都很適合(he)用 map() 方(fang)法,可(ke)以(yi)將轉換邏輯以(yi)lambda表達式的(de)形式放在 map() 方(fang)法里,就可(ke)以(yi)對集合(he)的(de)各(ge)個(ge)(ge)(ge)元素(su)進行轉換了,如下(xia)所示。

// 將字符串換成大(da)寫并用逗號鏈接起來
List<String> G7 = Arrays.asList("USA", "Japan", "France", "Germany", "Italy", "U.K.","Canada");
String G7Countries = G7.stream().map(x -> x.toUpperCase()).collect(Collectors.joining(", "));
System.out.println(G7Countries);

輸出:

USA, JAPAN, FRANCE, GERMANY, ITALY, U.K., CANADA

例9、復制不同的值,創建一個子列表

本例展示了如(ru)何利用流的 distinct() 方(fang)法來(lai)對(dui)集(ji)合(he)進行去重。

// 用所有(you)不同的(de)數字(zi)創建一個正方形列表
List<Integer> numbers = Arrays.asList(9, 10, 3, 4, 7, 3, 4);
List<Integer> distinct = numbers.stream().map( i -> i*i).distinct().collect(Collectors.toList());
System.out.printf("Original List : %s,  Square Without duplicates : %s %n", numbers, distinct);

輸出:

Original List : [9, 10, 3, 4, 7, 3, 4],  Square Without duplicates : [81, 100, 9, 16, 49]

例10、計算集合元素的最大值、最小值、總和以及平均值

IntStream、LongStream 和(he) DoubleStream 等流(liu)的類中,有個(ge)非常有用的方法(fa)(fa)叫做 summaryStatistics() 。可以(yi)返(fan)回 IntSummaryStatistics、LongSummaryStatistics 或者 DoubleSummaryStatistic s,描(miao)述流(liu)中元素的各種摘要(yao)數據。在本例中,我們用這個(ge)方法(fa)(fa)來計算列表的最大值(zhi)(zhi)和(he)最小值(zhi)(zhi)。它也有 getSum() 和(he) getAverage() 方法(fa)(fa)來獲得列表的所有元素的總(zong)和(he)及(ji)平均值(zhi)(zhi)。

//獲(huo)取數字(zi)的個(ge)數、最小值、最大值、總和以(yi)及(ji)平均(jun)值
List<Integer> primes = Arrays.asList(2, 3, 5, 7, 11, 13, 17, 19, 23, 29);
IntSummaryStatistics stats = primes.stream().mapToInt((x) -> x).summaryStatistics();
System.out.println("Highest prime number in List : " + stats.getMax());
System.out.println("Lowest prime number in List : " + stats.getMin());
System.out.println("Sum of all prime numbers : " + stats.getSum());
System.out.println("Average of all prime numbers : " + stats.getAverage());

輸出:

Highest prime number in List : 29
Lowest prime number in List : 2
Sum of all prime numbers : 129
Average of all prime numbers : 12.9

Lambda表達式 vs 匿名類

既然lambda表(biao)達(da)式(shi)(shi)即將正式(shi)(shi)取代(dai)Java代(dai)碼中(zhong)的(de)(de)匿名內部類,那么(me)有(you)必(bi)要(yao)對二者(zhe)做一個(ge)比較分析。一個(ge)關(guan)鍵(jian)的(de)(de)不(bu)同(tong)點就是關(guan)鍵(jian)字(zi) this。匿名類的(de)(de) this 關(guan)鍵(jian)字(zi)指向匿名類,而lambda表(biao)達(da)式(shi)(shi)的(de)(de) this 關(guan)鍵(jian)字(zi)指向包(bao)圍lambda表(biao)達(da)式(shi)(shi)的(de)(de)類。另一個(ge)不(bu)同(tong)點是二者(zhe)的(de)(de)編(bian)譯(yi)(yi)方(fang)式(shi)(shi)。Java編(bian)譯(yi)(yi)器(qi)將lambda表(biao)達(da)式(shi)(shi)編(bian)譯(yi)(yi)成類的(de)(de)私有(you)方(fang)法。使用了(le)Java 7的(de)(de) invokedynamic 字(zi)節碼指令來動(dong)態綁定這個(ge)方(fang)法。

Java 8 Lambda表達式要點

10個Java lambda表達式、流API示例

到目前為止(zhi)我們看(kan)到了(le)Java 8的(de)(de)10個lambda表(biao)達(da)式,這(zhe)對于新手來(lai)(lai)說(shuo)是個合適(shi)的(de)(de)任務(wu)量,你可能需要(yao)親自(zi)運行示例(li)程序以(yi)便掌握。試著修(xiu)改(gai)要(yao)求創(chuang)建自(zi)己的(de)(de)例(li)子,達(da)到快(kuai)速學(xue)習(xi)的(de)(de)目的(de)(de)。我還想建議大(da)家(jia)使用(yong)Netbeans IDE來(lai)(lai)練習(xi)lambda表(biao)達(da)式,它(ta)對Java 8支持良好。當(dang)把代碼(ma)轉換成函數式的(de)(de)時(shi)候,Netbeans會(hui)及時(shi)給你提(ti)示。只需跟著Netbeans的(de)(de)提(ti)示,就能很容易地把匿名類(lei)轉換成lambda表(biao)達(da)式。此外,如果(guo)你喜歡閱讀,那么記得看(kan)一(yi)下Java 8的(de)(de)lambdas,實用(yong)函數式編(bian)程這(zhe)本(ben)(ben)書(shu)(),作者(zhe)是Richard Warburton,或者(zhe)也可以(yi)看(kan)看(kan)Manning的(de)(de)Java 8實戰(zhan)(),這(zhe)本(ben)(ben)書(shu)雖然(ran)還沒(mei)出版,但我猜(cai)線上(shang)有第一(yi)章的(de)(de)免費pdf。不過,在你開始忙其它(ta)事情之前,先(xian)回顧一(yi)下Java 8的(de)(de)lambda表(biao)達(da)式、默認方法和函數式接口的(de)(de)重點知(zhi)識。

1)lambda表(biao)達式(shi)(shi)僅能放入如(ru)下(xia)代碼:預(yu)定義使用(yong)了(le) @Functional 注釋(shi)的(de)函(han)數(shu)式(shi)(shi)接(jie)口(kou),自帶一(yi)(yi)個(ge)(ge)抽(chou)象(xiang)函(han)數(shu)的(de)方(fang)法(fa),或(huo)者(zhe)SAM(Single Abstract Method 單(dan)個(ge)(ge)抽(chou)象(xiang)方(fang)法(fa))類型(xing)。這些(xie)稱為lambda表(biao)達式(shi)(shi)的(de)目(mu)標類型(xing),可以(yi)(yi)用(yong)作返回類型(xing),或(huo)lambda目(mu)標代碼的(de)參數(shu)。例如(ru),若一(yi)(yi)個(ge)(ge)方(fang)法(fa)接(jie)收(shou)Runnable、Comparable或(huo)者(zhe) Callable 接(jie)口(kou),都(dou)有單(dan)個(ge)(ge)抽(chou)象(xiang)方(fang)法(fa),可以(yi)(yi)傳入lambda表(biao)達式(shi)(shi)。類似的(de),如(ru)果一(yi)(yi)個(ge)(ge)方(fang)法(fa)接(jie)受聲(sheng)明于 java.util.function 包內的(de)接(jie)口(kou),例如(ru) Predicate、Function、Consumer 或(huo) Supplier,那么(me)可以(yi)(yi)向其傳lambda表(biao)達式(shi)(shi)。

2)lambda表(biao)達(da)式內可以使用(yong)方(fang)(fang)法(fa)(fa)(fa)引用(yong),僅(jin)當(dang)該方(fang)(fang)法(fa)(fa)(fa)不(bu)修改lambda表(biao)達(da)式提供的參數(shu)。本例中(zhong)的lambda表(biao)達(da)式可以換為(wei)方(fang)(fang)法(fa)(fa)(fa)引用(yong),因(yin)為(wei)這(zhe)僅(jin)是(shi)一個參數(shu)相同的簡單方(fang)(fang)法(fa)(fa)(fa)調用(yong)。

list.forEach(n -> System.out.println(n)); 
list.forEach(System.out::println);  // 使用(yong)方法引用(yong)

然而,若對參數(shu)有任何修改(gai),則不(bu)能使用方法引用,而需鍵(jian)入完整地lambda表達式,如(ru)下所(suo)示:

list.forEach((String s) -> System.out.println("*" + s + "*"));

事實上,可(ke)以(yi)省略這里的(de)lambda參數的(de)類(lei)型聲明,編譯器可(ke)以(yi)從列表的(de)類(lei)屬性(xing)推測出來。

3)lambda內(nei)部可以使用(yong)靜(jing)態(tai)、非靜(jing)態(tai)和(he)局(ju)部變量,這稱為lambda內(nei)的變量捕獲(huo)。

4)Lambda表(biao)達式在Java中又稱為閉包或匿名函(han)數,所以如果有(you)同(tong)事把它叫(jiao)閉包的時候,不(bu)用驚(jing)訝。

5)Lambda方法(fa)在編(bian)譯器內(nei)部被翻譯成(cheng)私有方法(fa),并派發 invokedynamic 字(zi)節碼指令來(lai)(lai)進行調用(yong)。可以使用(yong)JDK中的 javap 工具(ju)來(lai)(lai)反編(bian)譯class文(wen)件(jian)。使用(yong) javap -p 或 javap -c -v 命(ming)令來(lai)(lai)看一看lambda表達式(shi)生成(cheng)的字(zi)節碼。大致應該長這樣:

private static java.lang.Object lambda$0(java.lang.String);

6)lambda表(biao)達式有個限制,那(nei)就是只能引用 final 或 final 局部變量,這就是說不能在lambda內(nei)部修改(gai)定義在域外的變量。

List<Integer> primes = Arrays.asList(new Integer[]{2, 3,5,7});
int factor = 2;
primes.forEach(element -> { factor++; });
Compile time error : "local variables referenced from a lambda expression must be final or effectively final"

另(ling)外,只是訪問它而不作(zuo)修改是可(ke)以(yi)的(de),如下所示:

List<Integer> primes = Arrays.asList(new Integer[]{2, 3,5,7});
int factor = 2;
primes.forEach(element -> { System.out.println(factor*element); });

輸出:

4
6
10
14

因此,它(ta)看起來(lai)更像不可(ke)變閉包,類似于Python。

以上(shang)(shang)就(jiu)是Java 8的(de)lambda表達(da)式(shi)(shi)的(de)全部(bu)10個例子。此(ci)次修改將(jiang)成為Java史上(shang)(shang)最大的(de)一次,將(jiang)深遠影(ying)響未來Java開(kai)(kai)發(fa)(fa)(fa)者(zhe)使用(yong)集合框架(jia)的(de)方式(shi)(shi)。我(wo)想規模最相(xiang)似的(de)一次修改就(jiu)是Java 5的(de)發(fa)(fa)(fa)布了,它(ta)帶來了很(hen)多優點,提(ti)升了代碼質量,例如(ru):泛型、枚(mei)舉、自動裝箱(Autoboxing)、靜態(tai)導入(ru)、并(bing)發(fa)(fa)(fa)API和變量參數。上(shang)(shang)述特性使得Java代碼更加清(qing)晰,我(wo)想lambda表達(da)式(shi)(shi)也將(jiang)進一步改進它(ta)。我(wo)在(zai)期待著開(kai)(kai)發(fa)(fa)(fa)并(bing)行第三方庫,這可以使高(gao)性能應用(yong)變得更容易寫。

更多閱讀:

原文鏈接:  翻譯: - 
譯文鏈接: 
轉載請保留原文出處、譯者和譯文鏈接。]

posted on 2018-04-02 14:23  little fat  閱讀(152692)  評論(5)    收藏  舉報