最新国产好看的视频,伊人天堂AV在线,国产Aaaaaa视频,蜜臀视频在线观看一区,人妻av色图,密臀久久久精品影片,青青视频免费观看毛片,久草在线观看视,国产三级精品色情在线

java中l(wèi)ambda表達(dá)式語法說明

 更新時(shí)間:2016年09月11日 17:03:20   作者:robin  
“Lambda 表達(dá)式”(lambda expression)是一個(gè)匿名函數(shù),Lambda表達(dá)式基于數(shù)學(xué)中的λ演算得名,直接對應(yīng)于其中的lambda抽象(lambda abstraction),是一個(gè)匿名函數(shù),即沒有函數(shù)名的函數(shù)。Lambda表達(dá)式可以表示閉包(注意和數(shù)學(xué)傳統(tǒng)意義上的不同)。

語法說明

一個(gè)lambda表達(dá)式由如下幾個(gè)部分組成:

1. 在圓括號中以逗號分隔的形參列表。在CheckPerson.test方法中包含一個(gè)參數(shù)p,代表了一個(gè)Person類的實(shí)例。注意:lambda表達(dá)式中的參數(shù)的類型是可以省略的;此外,如果只有一個(gè)參數(shù)的話連括號也是可以省略的。比如上一節(jié)曾提到的代碼:

  p -> p.getGender() == Person.Sex.MALE
  && p.getAge() >= 18
      && p.getAge() <= 25

2. 箭頭符號:->。用來分隔參數(shù)和函數(shù)體。

3. 函數(shù)體。由一個(gè)表達(dá)式或代碼塊組成。在上一節(jié)的例子中使用了這樣的表達(dá)式:

p.getGender() == Person.Sex.MALE
      && p.getAge() >= 18
      && p.getAge() <= 25

如果使用的是表達(dá)式,java運(yùn)行時(shí)會計(jì)算并返回表達(dá)式的值。另外,還可以選擇在代碼塊中使用return語句:

  p -> {
    return p.getGender() == Person.Sex.MALE
        && p.getAge() >= 18
        && p.getAge() <= 25;
  }

不過return語句并不是表達(dá)式。在lambda表達(dá)式中需要將語句用花括號括起來,然而卻沒有必要在只是調(diào)用一個(gè)返回值為空的方法時(shí)也用花括號括起來,所以如下的寫法也是正確的:

  email -> System.out.println(email)

lambda表達(dá)式和方法的聲明看起來有很多類似的地方。所以也可以把lambda表達(dá)式視為匿名方法,也就是沒有定義名字的方法。

以上提到的lambda表達(dá)式都是只使用了一個(gè)參數(shù)作為形參的表達(dá)式。下面的實(shí)例類,Caulator,演示了如何使用多個(gè)參數(shù)作為形參:

package com.zhyea.zytools;

public class Calculator {

  interface IntegerMath {
    int operation(int a, int b);
  }

  public int operateBinary(int a, int b, IntegerMath op) {
    return op.operation(a, b);
  }

  public static void main(String... args) {
    Calculator myApp = new Calculator();
    IntegerMath addition = (a, b) -> a + b;
    IntegerMath subtraction = (a, b) -> a - b;
    System.out.println("40 + 2 = " + myApp.operateBinary(40, 2, addition));
    System.out.println("20 - 10 = " + myApp.operateBinary(20, 10, subtraction));
  }
}

代碼中operateBinary方法使用了兩個(gè)整型參數(shù)執(zhí)行算數(shù)操作。這里的算數(shù)操作本身就是IntegerMath接口的一個(gè)實(shí)例。在上面的程序中使用lambda表達(dá)式定義了兩個(gè)算數(shù)操作:addition和subtraction。執(zhí)行程序會打印如下內(nèi)容:

40 + 2 = 42
20 - 10 = 10

訪問外部類的局部變量

類似于局部類或匿名類,lambda表達(dá)式也可以訪問外部類的局部變量。不同的是,使用lambda表達(dá)式時(shí)無需考慮覆蓋之類的問題。lambda表達(dá)式只是一個(gè)詞法上的概念,這意味著它不需要從超類中繼承任何名稱,也不會引入新的作用域。也就是說,在lambda表達(dá)式中的聲明和在它的外部環(huán)境中的聲明意義是一樣的。在下面的例子中對此作了演示:

package com.zhyea.zytools;

import java.util.function.Consumer;

public class LambdaScopeTest {

  public int x = 0;

  class FirstLevel {

    public int x = 1;

    void methodInFirstLevel(int x) {
      //如下的語句會導(dǎo)致編譯器在statement A處報(bào)錯(cuò)“l(fā)ocal variables referenced from a lambda expression must be final or effectively final”
      // x = 99;
      Consumer<integer> myConsumer = (y) ->{
        System.out.println("x = " + x); // Statement A
        System.out.println("y = " + y);
        System.out.println("this.x = " + this.x);
        System.out.println("LambdaScopeTest.this.x = " + LambdaScopeTest.this.x);
      };

      myConsumer.accept(x);
    }
  }

  public static void main(String... args) {
    LambdaScopeTest st = new LambdaScopeTest();
    LambdaScopeTest.FirstLevel fl = st.new FirstLevel();
    fl.methodInFirstLevel(23);
  }
}

這段代碼會輸出如下內(nèi)容:

x = 23
y = 23
this.x = 1
LambdaScopeTest.this.x = 0

如果使用示例中l(wèi)ambda表達(dá)式myConsumer中的參數(shù)y替換為x,編譯器就會報(bào)錯(cuò):

 

  Consumer<integer> myConsumer = (x) ->{
        // ....
      };

編譯器報(bào)錯(cuò)信息是:“variable x is already defined in method methodInFirstLevel(int)”,就是說在方法methodInFirstLevel中已經(jīng)定義了變量x。報(bào)錯(cuò)是因?yàn)閘ambda表達(dá)式不會引入新的作用域。也因此呢,可以在lambda表達(dá)式中直接訪問外部類的域字段、方法以及形參。在這個(gè)例子中,lambda表達(dá)式myConsumer直接訪問了方法methodInFirstLevel的形參x。而訪問外部類的成員時(shí)也是直接使用this關(guān)鍵字。在這個(gè)例子中this.x指的就是FirstLevel.x。

然而,和局部類或匿名類一樣,lambda表達(dá)式也只能訪問局部變量或外部被聲明為final(或等同于final)的成員。比如,我們將示例代碼methodInFirstLevel方法中“x=99”前面的注釋去掉:

      //如下的語句會導(dǎo)致編譯器在statement A處報(bào)錯(cuò)“l(fā)ocal variables referenced from a lambda expression must be final or effectively final”
      x = 99;
      Consumer<integer> myConsumer = (y) ->{
        System.out.println("x = " + x); // Statement A
        System.out.println("y = " + y);
        System.out.println("this.x = " + this.x);
        System.out.println("LambdaScopeTest.this.x = " + LambdaScopeTest.this.x);
      };

因?yàn)樵谶@段語句中修改了參數(shù)x的值,使得methodInFirstLevel的參數(shù)x不可以再被視為final式的。因此java編譯器就會在lambda表達(dá)式訪問局部變量x的地方報(bào)出類似“l(fā)ocal variables referenced from a lambda expression must be final or effectively final”這樣的錯(cuò)誤。

目標(biāo)類型

該如何判斷l(xiāng)ambda表達(dá)式的類型呢。再來看一下篩選適齡服兵役人員的代碼:

   p -> p.getGender() == Person.Sex.MALE
          && p.getAge() >= 18
          && p.getAge() <= 25

這段代碼在兩處用到過:

public static void printPersons(List<Person> roster, CheckPerson tester) —— 方案三
public void printPersonsWithPredicate(List<Person> roster, Predicate<Person> tester) —— 方案六

在調(diào)用printPersons方法時(shí),這個(gè)方法期望一個(gè)CheckPerson 類型的參數(shù),此時(shí)上面的那個(gè)表達(dá)式就是一個(gè)CheckPerson 類型的表達(dá)式。在調(diào)用printPersonsWithPredicate方法時(shí),期望一個(gè)Predicate<Person>類型的參數(shù),此時(shí)同樣的表達(dá)式就是Predicate<Person>類型的。像這樣子的,由方法期望的類型來決定的類型就叫做目標(biāo)類型(其實(shí)我覺得scala中的類型推斷用在這里更合適)。java編譯器就是通過目標(biāo)類型的上下文語境或者發(fā)現(xiàn)lambda表達(dá)式時(shí)的位置來判斷l(xiāng)ambda表達(dá)式的類型的。這也就意味著只能在Java編譯器可以推斷出類型的位置使用Lambda表達(dá)式:

  1. 變量聲明;
  2. 賦值;
  3. 返回語句;
  4. 數(shù)組初始化;
  5. 方法或者構(gòu)造器參數(shù);
  6. lambda表達(dá)式方法體;
  7. 條件表達(dá)式(?:);
  8. 拋出異常時(shí)。

目標(biāo)類型和方法參數(shù)

對于方法參數(shù),Java編譯器還需要依賴兩個(gè)語言特性來決定目標(biāo)類型:重載解析和類型參數(shù)推斷。

看一下下面的這兩個(gè)函數(shù)式接口( java.lang.Runnable and java.util.concurrent.Callable<V>):

public interface Runnable {
    void run();
  }

  public interface Callable<v> {
    V call();
  }

Runnable.run()方法沒有返回值,而Callable.call()方法有。

假設(shè)我們像下面這樣重載了invoke方法:

 void invoke(Runnable r) {
    r.run();
  }

  <t> T invoke(Callable<t> c) {
    return c.call();
  }

那么在下面的語句中將會調(diào)用哪個(gè)方法呢:

String s = invoke(() -> "done");

調(diào)用的是invoke(Callable<T>),因?yàn)檫@個(gè)方法有返回值,而invoke(Runnable<T>)沒有返回值。在這種情況下lambda表達(dá)式(() -> “done”)的類型是Callable<T>。

序列化

如果一個(gè)lambda表達(dá)式的目標(biāo)類型還有它調(diào)用的參數(shù)的類型都是可序列化的,那么lambda表達(dá)式也是可序列化的。然而就像內(nèi)部類一樣,強(qiáng)烈不建議對lambda表達(dá)式進(jìn)行序列化。

相關(guān)文章

  • Java中的IO讀寫原理詳解

    Java中的IO讀寫原理詳解

    這篇文章主要介紹了Java中的IO讀寫原理,IO是指輸入和輸出操作的技術(shù),它提供了一組用于讀取和寫入數(shù)據(jù)的類,以及用于處理字符和字節(jié)數(shù)據(jù)的接口,這些類和接口可以用于讀取和寫入文件、網(wǎng)絡(luò)流、內(nèi)存緩沖區(qū)等各種數(shù)據(jù)源和目標(biāo),需要的朋友可以參考下
    2023-08-08
  • Java中的CAS鎖機(jī)制(無鎖、自旋鎖、樂觀鎖、輕量級鎖)詳解

    Java中的CAS鎖機(jī)制(無鎖、自旋鎖、樂觀鎖、輕量級鎖)詳解

    這篇文章主要介紹了Java中的CAS鎖機(jī)制(無鎖、自旋鎖、樂觀鎖、輕量級鎖)詳解,CAS算法的作用是解決多線程條件下使用鎖造成性能損耗問題的算法,保證了原子性,這個(gè)原子操作是由CPU來完成的,需要的朋友可以參考下
    2024-01-01
  • Java如何批量執(zhí)行datax腳本

    Java如何批量執(zhí)行datax腳本

    這篇文章主要介紹了Java如何批量執(zhí)行datax腳本問題,具有很好的參考價(jià)值,希望對大家有所幫助,如有錯(cuò)誤或未考慮完全的地方,望不吝賜教
    2024-02-02
  • 基于java實(shí)現(xiàn)websocket代碼示例

    基于java實(shí)現(xiàn)websocket代碼示例

    這篇文章主要介紹了基于java實(shí)現(xiàn)websocket代碼示例,文中通過示例代碼介紹的非常詳細(xì),對大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價(jià)值,需要的朋友可以參考下
    2020-12-12
  • MyBatis中的循環(huán)插入insert foreach問題

    MyBatis中的循環(huán)插入insert foreach問題

    這篇文章主要介紹了MyBatis中的循環(huán)插入insert foreach問題,具有很好的參考價(jià)值,希望對大家有所幫助,如有錯(cuò)誤或未考慮完全的地方,望不吝賜教
    2023-11-11
  • SpringCloud-Spring?Boot?Starter使用測試及問題小結(jié)

    SpringCloud-Spring?Boot?Starter使用測試及問題小結(jié)

    Spring?Boot?Starter?是在?SpringBoot?組件中被提出來的一種概念、簡化了很多煩瑣的配置、通過引入各種?Spring?Boot?Starter?包可以快速搭建出一個(gè)項(xiàng)目的腳手架,這篇文章主要介紹了SpringCloud-Spring?Boot?Starter使用測試,需要的朋友可以參考下
    2022-07-07
  • Springboot配置@Async無效的解決方案

    Springboot配置@Async無效的解決方案

    這篇文章主要介紹了Springboot配置@Async無效的解決方案,具有很好的參考價(jià)值,希望對大家有所幫助,如有錯(cuò)誤或未考慮完全的地方,望不吝賜教
    2023-09-09
  • Java使用JDBC連接postgresql數(shù)據(jù)庫示例

    Java使用JDBC連接postgresql數(shù)據(jù)庫示例

    這篇文章主要介紹了Java使用JDBC連接postgresql數(shù)據(jù)庫,結(jié)合實(shí)例形式分析了jdbc連接postgresql數(shù)據(jù)庫及數(shù)值插入、更新、查詢等相關(guān)操作技巧,需要的朋友可以參考下
    2019-01-01
  • MybatisPlus保存、讀取MySQL中的json字段失敗問題及解決

    MybatisPlus保存、讀取MySQL中的json字段失敗問題及解決

    這篇文章主要介紹了MybatisPlus保存、讀取MySQL中的json字段失敗問題及解決方案,具有很好的參考價(jià)值,希望對大家有所幫助。如有錯(cuò)誤或未考慮完全的地方,望不吝賜教
    2022-07-07
  • 基于JavaBean編輯器讀取peroperties文件的實(shí)例

    基于JavaBean編輯器讀取peroperties文件的實(shí)例

    下面小編就為大家?guī)硪黄贘avaBean編輯器讀取peroperties文件的實(shí)例。小編覺得挺不錯(cuò)的,現(xiàn)在就分享給大家,也給大家做個(gè)參考。一起跟隨小編過來看看吧
    2017-10-10

最新評論

鄂温| 五华县| 甘孜| 南溪县| 河东区| 和平县| 永新县| 两当县| 威海市| 囊谦县| 巩义市| 饶平县| 嘉义市| 科技| 广灵县| 大埔县| 兴安盟| 扶沟县| 陆丰市| 田林县| 广东省| 寻乌县| 乐陵市| 绥棱县| 台湾省| 芒康县| 郸城县| 满城县| 南充市| 无极县| 甘孜县| 滕州市| 太谷县| 兖州市| 青铜峡市| 延长县| 克东县| 鄂州市| 清水县| 旌德县| 陕西省|