国产 无码 综合区,色欲AV无码国产永久播放,无码天堂亚洲国产AV,国产日韩欧美女同一区二区

淺談 Java 中的 Lambda 表達式

這篇具有很好參考價值的文章主要介紹了淺談 Java 中的 Lambda 表達式。希望對大家有所幫助。如果存在錯誤或未考慮完全的地方,請大家不吝賜教,您也可以點擊"舉報違法"按鈕提交疑問。

更好的閱讀體驗 \huge{\color{red}{更好的閱讀體驗}} 更好的閱讀體驗
Lambda 表達式是一種匿名函數(shù),它可以作為參數(shù)傳遞給方法或存儲在變量中。在 Java8 中,它和函數(shù)式接口一起,共同構(gòu)建了函數(shù)式編程的框架。


什么是函數(shù)式編程


函數(shù)式編程是一種編程范式,也是一種思想。

它將計算視為函數(shù)求值的過程,并強調(diào)函數(shù)的純粹性和不可變性。在函數(shù)式編程中,函數(shù)被視為一等公民,可以作為參數(shù)傳遞、存儲在變量中,并且函數(shù)的執(zhí)行不會產(chǎn)生副作用。

例如,我們想要輸出 List 中的全部元素,命令式編程看起來是下面這樣:

public class Main {
    public static void main(String[] args) {
        List<Integer> list = Arrays.asList(1, 2, 3, 4, 5);
        for (Integer item : list) {
            System.out.println(item);
        }       
    }
}

而在函數(shù)式編程的思想下,代碼則看起來是下面這樣:

public class Main {
    public static void main(String[] args) {
        List<Integer> list = Arrays.asList(1, 2, 3, 4, 5);
        list.forEach(System.out::println);
    }
}

從以上的兩個例子中,可以看出,命令式編程需要我們自己去實現(xiàn)具體的邏輯細節(jié)。而函數(shù)式編程則是調(diào)用 API 完成需求的實現(xiàn),將原本命令式的代碼寫成一系列嵌套的函數(shù)調(diào)用。

由此可見,在函數(shù)式編程的思想下,我們將功能的具體細節(jié)隱藏,將其抽象為了函數(shù)式接口,這就使得具有規(guī)范、穩(wěn)定、可組合、高復(fù)用的特點。


Lambda 與匿名內(nèi)部類


既然函數(shù)式編程需要將功能抽象為接口,那么我們來回顧一下接口的使用。

接口作為 java 中的一種抽象類型,它定義了一組方法的簽名(方法名、參數(shù)列表和返回類型),但沒有具體的實現(xiàn)。

因此,要使用接口,就必須提供相應(yīng)的實現(xiàn)類,或者包含實現(xiàn)接口的對象返回。例如,要想使用 List 接口,我們可以使用實現(xiàn)了該接口的實現(xiàn)類 ArrayList、LinkdeList 等,或者像上節(jié)例子一樣,使用 Arrays.asList 的工廠方法返回了一個實現(xiàn)了 List 接口的 ArrayList 對象。

其中,對于實現(xiàn)類來說,由于接口只需要實現(xiàn)某種功能,我們完全可以使用匿名內(nèi)部類來實現(xiàn),例如,我們把輸出 List 的全部元素抽象為一個接口 Show,其中提供了一個函數(shù)方法 ShowAllItems

public interface Show {
    void ShowAllItems(List<Integer> arrayList);
}

繼續(xù)沿用之前代碼示例,現(xiàn)在要求輸出 List 中的全部元素:

public class Main {
    public static void main(String[] args) {
        List<Integer> list = Arrays.asList(1, 2, 3, 4, 5);
        Show show = new Show() {
            @Override
            public void ShowAllItems(List<Integer> arrayList) {
                for (Integer item : arrayList) System.out.println(item);
            }
        };
        show.ShowAllItems(list);
    }
}

上述代碼中,由于接口 Show 其中只有一個抽象方法 ShowAllItems,如果單獨為該接口實現(xiàn)一個類未免顯得太過笨拙,因此我們在使用時直接使用匿名內(nèi)部類的實現(xiàn),通過這種方式創(chuàng)建一個臨時的實現(xiàn)子類,這就令接口的使用更加靈活。

那么問題來了,如果我們后續(xù)仍要使用多次該接口,每次使用都以匿名內(nèi)部類的方式來實現(xiàn),會導(dǎo)致我們的代碼太過臃腫,有沒有更好的解決辦法呢?

當然有的,這就是我們今天討論的主人公—— Lambda 表達式,如果一個接口中有且只有一個待實現(xiàn)的抽象方法,那么我們可以將匿名內(nèi)部類簡寫為 Lambda 表達式:

public class Main {
    public static void main(String[] args) {
        List<Integer> list = Arrays.asList(1, 2, 3, 4, 5);
        Show show = param -> {
            for (Integer item : param) System.out.println(item);
        };
        show.ShowAllItems(list);
    }
}

也許上面的示例會使你感到困惑,下面我們來詳細探討一下 Lambda 表達式的基礎(chǔ)語法。


Lambda 表達式基礎(chǔ)語法


  • 標準格式為:([參數(shù)類型 參數(shù)名稱,]...) ‐> { 代碼語句,包括返回值 }
  • 和匿名內(nèi)部類不同,Lambda 表達式僅支持接口,不支持抽象類。
  • 接口內(nèi)部必須有且僅有一個抽象方法(可以有多個方法,但是必須保證其他方法有默認實現(xiàn),必須留一個抽象方法出來)
  • Lambda 表達式可以在函數(shù)體中引用外部的變量,從而實現(xiàn)了閉包,但對進入閉包的變量有 final 的限制。

接下來,我們看一個簡單示例,假設(shè)接口 Test 中有且僅有如下抽象方法:

public interface Test {
    String showTestNumber(Integer param);
}

利用上述接口,我們使用如下匿名內(nèi)部類來實現(xiàn)該方法:

public class Main {
    public static void main(String[] args) {
        Test test = new Test() {
            @Override
            public String showTestNumber(Integer param) {
                return "Test number is " + param;
            }
        };
        System.out.println(test.showTestNumber(114));
    }
}

如果將其轉(zhuǎn)換為 Lambda 的標準格式,則為:

public class Main {
    public static void main(String[] args) {
        Test test = (Integer param) -> {
            return "Test number is " + param;
        };
        System.out.println(test.showTestNumber(514));
    }
}

由于該方法只需傳遞一個參數(shù),因此可以省略參數(shù)類型及其括號:

public class Main {
    public static void main(String[] args) {
        Test test = param -> {
            return "Test number is " + param;
        };
        System.out.println(test.showTestNumber(1919));
    }
}

又因為方法實現(xiàn)只有一條 return 語句,則后面的 { ... } 也可以省略:

public class Main {
    public static void main(String[] args) {
        Test test = param -> "Test number is " + param;
        System.out.println(test.showTestNumber(810));
    }
}

此外,如果方法已經(jīng)實現(xiàn),我們可以利用方法引用:

public class Main {
    public static void main(String[] args) {
        Test test = Main::showTestNumber;
        System.out.println(test.showTestNumber(721));
    }

    // 提取方法實現(xiàn)
    private static String showTestNumber(Integer param) {
        return "Test number is " + param;
    }
}

在上述示例代碼中,Main::showTestNumber是一個方法引用,它引用了 Main 類中的靜態(tài)方法 showTestNumber。該方法被賦值給 Test接口的實例變量 test

關(guān)于方法引用的使用,我們在后面還會重新提到。但這里我需要先介紹一下關(guān)于閉包的特性。

閉包是一個函數(shù)(或過程),它可以訪問并操作其作用域外部的變量。在 Java 中,可以通過 Lambda 表達式或方法引用來創(chuàng)建閉包。

其實,在 main 方法中,我們還可以通過調(diào)用 test.showTestNumber 來調(diào)用閉包。閉包中的方法 showTestNumber 可以訪問并操作其作用域外部的變量。

為了更清晰地展示 Lambda 的閉包過程,我們使用如下示例:

public class Main {
    public static void main(String[] args) {
        String Claim = "Test number is ";
        Test test = param -> Claim + param;
        System.out.println(test.showTestNumber(2333));
    }
}

在上述示例代碼中,Lambda 表達式捕獲了外部變量 Claim,并在 Lambda 表達式的范圍之外(main()方法內(nèi)部)調(diào)用閉包時仍然可以訪問和使用該變量。

注意Java8 不要求顯式將閉包變量聲明為 final,但如果你嘗試修改閉包變量的值,則會報錯。

public class Main {
    public static void main(String[] args) {
        String Claim = "Test number is ";
        Claim = "Yeah~ The number is ";  // 從lambda 表達式引用的本地變量必須是最終變量或?qū)嶋H上的最終變量
        Test test = param -> Claim + param;  
        System.out.println(test.showTestNumber(2333));
    }
}

Lambda 的應(yīng)用


好了,你已經(jīng)學會 1 + 1 = 2 1 + 1 = 2 1+1=2 了,現(xiàn)在來康康更實際的東西吧(


無參的函數(shù)式接口


以最常用的 Runnable 接口為例:

Java8 之前,如果需要新建一個線程,使用匿名內(nèi)部類的寫法是這樣:

public class Main {
    public static void main(String[] args) {
        Runnable runnable = new Runnable() {
            @Override
            public void run() {
                System.out.println("哼哼哼啊啊啊~");
            }
        };
        runnable.run();
    }
}

如果使用 Lambda 表達式則看起來是這樣;

public class Main {
    public static void main(String[] args) {
        Runnable runnable = () -> System.out.println("哼哼哼啊啊啊~");
        runnable.run();
    }
}

我們來看一下具體的 Runnable 接口:

@FunctionalInterface
public interface Runnable {
    public abstract void run();
}

可以看到該接口上面有 @FunctionalInterface 注解,該注解標識了一個接口是函數(shù)式接口。因此,我們可以使用 Lambda 表達式將匿名內(nèi)部類進行替換。

值得注意的是,@FunctionalInterface 注解并不是必須的,它只是作為一種提示和約束的工具。當我們在定義接口時,如果希望該接口只包含一個抽象方法,以便可以使用 Lambda 表達式或方法引用進行函數(shù)式編程,可以選擇添加 @FunctionalInterface 注解來明確表達這個意圖。

即使沒有添加 @FunctionalInterface 注解,只要該接口符合函數(shù)式接口的定義(只有一個抽象方法),它仍然可以用于函數(shù)式編程。


帶參的函數(shù)式接口


這里假設(shè)我們需要對一個數(shù)組進行排序:

Java8 之前,對數(shù)組進行排序可以使用 Arrays.sort 方法,如果需要指定排序規(guī)則,只需要實現(xiàn)其中的 Comparator 方法即可:

public class Main {
    public static void main(String[] args) {
        Integer[] array = new Integer[]{4, 5, 9, 3, 2, 8, 1, 0, 6};
        Arrays.sort(array, new Comparator<Integer>() {
            @Override
            public int compare(Integer o1, Integer o2) {
                return o1 - o2;
            }
        });
        System.out.println(Arrays.toString(array)); //按從小到大的順序排列
    } 
}

轉(zhuǎn)換為 Lambda 表達式可以是下面這樣:

public class Main {
    public static void main(String[] args) {
        Integer[] array = new Integer[]{4, 5, 9, 3, 2, 8, 1, 0, 6};
        Arrays.sort(array, (o1, o2) -> o1 - o2);
        System.out.println(Arrays.toString(array)); //按從小到大的順序排列
    }
}

方法引用


Java 方法引用是一種簡化 Lambda 表達式的語法,用于直接引用已經(jīng)存在的方法。方法引用可以通過以下幾種方式來表示:

  1. 靜態(tài)方法引用:引用靜態(tài)方法,使用類名或者接口名作為前綴,后面跟上方法名。例如我們在之前例子中介紹過的 Main::showTestNumber。

  2. 實例方法引用:引用非靜態(tài)方法,使用對象名或者對象引用作為前綴,后面跟上方法名。例如,objectName::instanceMethodName

  3. 特定類的任意對象方法引用:引用特定類的實例方法,使用類名作為前綴,后面跟上方法名。例如,ClassName::instanceMethodName。

  4. 構(gòu)造方法引用:引用構(gòu)造方法,使用類名后面跟上 new 關(guān)鍵字。例如,ClassName::new。

  5. 數(shù)組構(gòu)造方法引用:引用數(shù)組的構(gòu)造方法,使用數(shù)組類型后面跟上 new 關(guān)鍵字。例如,TypeName[]::new。

需要注意的是,方法引用的適用條件是被引用的方法的簽名(參數(shù)類型和返回類型)必須與函數(shù)式接口中的抽象方法的參數(shù)類型和返回類型相匹配。

我們使用上節(jié)數(shù)組排序的情景進行舉例,即使我們已經(jīng)利用 Lambda 表達式進行了大幅度的簡化,但是這還不夠,我們觀察 Integer 類,其中有一個叫做 compare 的靜態(tài)方法:

public static int compare(int x, int y) {
    return (x < y) ? -1 : ((x == y) ? 0 : 1);
}

該方法是一個靜態(tài)方法,但是它卻和 Comparator 需要實現(xiàn)的方法返回值和參數(shù)定義一模一樣,因此我們直接進行方法引用:

public class Main {
    public static void main(String[] args) {
        Integer[] array = new Integer[]{4, 5, 9, 3, 2, 8, 1, 0, 6};
        Arrays.sort(array, Integer::compare);
        System.out.println(Arrays.toString(array)); //按從小到大的順序排列
    }
}

如果不使用靜態(tài)方法,而使用普通的成員方法,即在 Comparator 中,我們需要實現(xiàn)的方法為:

public int compare(Integer o1, Integer o2) {
     return o1 - o2;
}

其中 o1o2 都是 Integer 類型,而在 Integer 類中有一個 compareTo 方法:

public int compareTo(Integer anotherInteger) {
    return compare(this.value, anotherInteger.value);
}

如果是以匿名內(nèi)部類的方式實現(xiàn),那么代碼如下:

public class Main {
    public static void main(String[] args) {
        Integer[] array = new Integer[]{4, 5, 9, 3, 2, 8, 1, 0, 6};
        Arrays.sort(array, new Comparator<Integer>() {
            @Override
            public int compare(Integer o1, Integer o2) {
                return o1.compareTo(o2);
            }
        });
        System.out.println(Arrays.toString(array)); //按從小到大的順序排列
    }
}

繼續(xù)將上述匿名內(nèi)部類替換為 Lambda 表達式如下:

public class Main {
    public static void main(String[] args) {
        Integer[] array = new Integer[]{4, 5, 9, 3, 2, 8, 1, 0, 6};
        Arrays.sort(array, (o1, o2) -> o1.compareTo(o2));
        System.out.println(Arrays.toString(array)); //按從小到大的順序排列
    }
}

由于該方法并非靜態(tài)方法,而是所屬的實例對象所有,如果我們想要引用該方法,我們需要進行實例方法引用:

public class Main {
    public static void main(String[] args) {
        Integer[] array = new Integer[]{4, 5, 9, 3, 2, 8, 1, 0, 6};
        Arrays.sort(array, Integer::compareTo);
        System.out.println(Arrays.toString(array)); //按從小到大的順序排列
    }
}

雖然看起來和剛才的靜態(tài)方法引用沒有什么區(qū)別,但實際上,當我們使用非靜態(tài)方法時,會使用抽象方參數(shù)列表的第一個作為目標對象,后續(xù)參數(shù)作為目標對象成員方法的參數(shù),即 o1 作為目標對象,o2 作為參數(shù),正好匹配了 compareTo 方法。

對于構(gòu)造方法引用,假設(shè)接口 Test 中有抽象方法 newTest

public interface Test {
    String newTest(String param);
}

對于普通的 Lambda 替換,代碼如下:

public class Main {
    public static void main(String[] args) {
        Test test = param -> param;
        System.out.println(test.newTest("哼哼哼啊啊啊~"));
    }
}

而我們注意到該方法其實就是 String 中的構(gòu)造方法,因此我們直接進行構(gòu)造方法引用:

public class Main {
    public static void main(String[] args) {
        Test test = String::new;
        System.out.println(test.newTest("哼哼哼啊啊啊~"));
    }
}

Lambda 表達式的本質(zhì)


經(jīng)過上面的學習,相信你已經(jīng)可以熟練地使用 Lambda 表達式了,看起來 Lambda 只是一種簡化匿名內(nèi)部類進行實現(xiàn)接口的語法糖,但實際上,它們是兩種本質(zhì)不同的事物:

  • 匿名內(nèi)部類本質(zhì)是一個類,只是不需要我們顯示地指定類名,編譯器會自動為該類取名。
  • Lambda 表達式本質(zhì)是一個函數(shù),當然,編譯器也會為它取名,在 JVM 層面,這是通過 invokedynamic 指令實現(xiàn)的,編譯器會將 Lambda 表達式轉(zhuǎn)化為一個私有方法,并在需要的時候動態(tài)地生成一個函數(shù)式接口的實例。

假設(shè)我們使用上述 Runnable 的匿名內(nèi)部類的代碼進行編譯,可以看到結(jié)果如下:

淺談 Java 中的 Lambda 表達式,java,開發(fā)語言

可以看到, Main$1.class 實際上就是 Main 類中生成的匿名內(nèi)部類文件,而將其替換為 Lambda 表達式后編譯的結(jié)果如下:

淺談 Java 中的 Lambda 表達式,java,開發(fā)語言

沒有生成單獨的類文件,即,匿名內(nèi)部類對應(yīng)的是一個 class 文件,而 Lambda 表達式對應(yīng)的是它所在主類的一個私有方法。文章來源地址http://www.zghlxwxcb.cn/news/detail-677680.html


參考文獻


  • Java中的函數(shù)式編程
  • Java Lambda 表達式介紹
  • 在Java代碼中寫Lambda表達式是種怎樣的體驗

到了這里,關(guān)于淺談 Java 中的 Lambda 表達式的文章就介紹完了。如果您還想了解更多內(nèi)容,請在右上角搜索TOY模板網(wǎng)以前的文章或繼續(xù)瀏覽下面的相關(guān)文章,希望大家以后多多支持TOY模板網(wǎng)!

本文來自互聯(lián)網(wǎng)用戶投稿,該文觀點僅代表作者本人,不代表本站立場。本站僅提供信息存儲空間服務(wù),不擁有所有權(quán),不承擔相關(guān)法律責任。如若轉(zhuǎn)載,請注明出處: 如若內(nèi)容造成侵權(quán)/違法違規(guī)/事實不符,請點擊違法舉報進行投訴反饋,一經(jīng)查實,立即刪除!

領(lǐng)支付寶紅包贊助服務(wù)器費用

相關(guān)文章

  • 進階JAVA篇- Lambda 表達式與 Lambda 表達式的省略規(guī)則

    進階JAVA篇- Lambda 表達式與 Lambda 表達式的省略規(guī)則

    目錄 ? ? ? ? 1.0 什么是 Lambda 表達式? ? ? ? ? 1.1 既然跟匿名內(nèi)部類相關(guān),先來回顧匿名內(nèi)部類。 ? ? ? ? ?1.2 Lambda 表達式與匿名內(nèi)部類之間的關(guān)系。 ? ? ? ? 1.3 函數(shù)式接口 ? ? ? ? 1.4 在具體代碼中來操作一下 ? ? ? ? 2.0?Lambda 表達式省略規(guī)則 ??????? ?Lambda 表達

    2024年02月08日
    瀏覽(29)
  • Java- Lambda表達式

    目錄 一、Lambda簡介 二、Lambda使用前提 三、Lambda語法 1.操作符 a.\\\"-\\\" ?b.\\\"::\\\" 2.格式? a.無參數(shù) b.有參數(shù) 四、Lambda演化過程 五、Lambda實現(xiàn)排序 Lambda 表達式,也可稱為閉包,它是推動 Java 8 發(fā)布的最重要新特性。Lambda 允許把函數(shù)作為一個方法的參數(shù)(函數(shù)作為參數(shù)傳遞進方法中)

    2024年02月03日
    瀏覽(28)
  • Java Lambda表達式

    1.1 函數(shù)式編程思想概括 在數(shù)學中,函數(shù)就是有輸入量、輸出量的一套計算方案,也就是“拿數(shù)據(jù)做操作” 面向?qū)ο笏枷霃娬{(diào)“必須通過對象的形式來做事情” 函數(shù)式思想則盡量忽略面

    2024年02月07日
    瀏覽(42)
  • Java Lambda 表達式

    Java Lambda 表達式

    ??wei_shuo的個人主頁 ??wei_shuo的學習社區(qū) ??Hello World ! Java Lambda 表達式是 Java 8 引入的一種函數(shù)式編程特性,它是一種輕量級的匿名函數(shù),允許我們將函數(shù)作為方法的參數(shù)進行傳遞。Lambda 表達式可以理解為是一種簡潔的方式來表示可傳遞的代碼塊,它可以替代傳統(tǒng)的匿名內(nèi)

    2024年02月08日
    瀏覽(34)
  • Lambda表達式(JAVA)

    Lambda表達式(JAVA)

    注:如果沒有學過 匿名內(nèi)部類 和 接口 不推薦往下看。 (parameters) - expression 或 (parameters) -{ statements; } parameters:表示參數(shù)列表; -:可理解為“被用于”的意思; expression:表示一條語句; statements:表示多條語句。 Lambda可以理解為:Lambda就是匿名內(nèi)部類的簡化。 lambda表達式

    2024年02月08日
    瀏覽(28)
  • java lambda表達式詳解

    java lambda表達式詳解

    我們知道,在Java中,接口是不能實例化的,但是接口對象可以指向它的實現(xiàn)類對象。如果接口連實現(xiàn)對象都沒有呢?那還可以使用匿名類的方式,如下: 復(fù)制 但是,使用匿名內(nèi)部的方式,代碼量其實并不是非常簡潔,而為了使代碼更加的簡潔,Java引進了 Lambda 表達式的寫法,

    2024年02月03日
    瀏覽(34)
  • Java學習——lambda表達式

    Java學習——lambda表達式

    什么是Lambda表達式? 可以將Lambda表達式理解為一個匿名函數(shù); Lambda表達式允許將一個函數(shù)作為另外一個函數(shù)的參數(shù); 我們可以把 Lambda 表達式理解為是一段可以傳遞的代碼(將代碼作為實參),也可以理解為函數(shù)式編程, 將一個函數(shù)作為參數(shù)進行傳遞 。 為什么要引入Lambda表

    2024年02月04日
    瀏覽(38)
  • 【Java基礎(chǔ)】Java Lambda表達式詳解

    【Java基礎(chǔ)】Java Lambda表達式詳解

    Lambda 表達式,即函數(shù)式編程是 JDK8 的一個新特性,也被稱為閉包,Lambda表達式允許把函數(shù)作為一個方法的參數(shù),即行為參數(shù)化,函數(shù)作為參數(shù)傳遞進方法中。 Lambda表達式可以取代大部分的匿名內(nèi)部類,寫出更優(yōu)雅的 Java 代碼,尤其在集合的遍歷和其他集合操作中,可以極大

    2024年02月04日
    瀏覽(25)
  • 【JAVA】包裝類、正則表達式、Arrays類、Lambda表達式

    包裝類是8種基本數(shù)據(jù)類型對應(yīng)的引用類型 作用:后期的集合和泛型不支持基本類型,只能使用包裝類 基本數(shù)據(jù)類型和其對應(yīng)的引用數(shù)據(jù)類型的變量可以互相賦值 基本數(shù)據(jù)類型 引用數(shù)據(jù)類型 byte Byte short Short int Integer long Long char Character float Float double Double boolean Boolean 包裝類

    2024年02月13日
    瀏覽(33)
  • Java新特性:Lambda表達式

    Java新特性:Lambda表達式

    Java新特性:Lambda表達式 Lambda 表達式(Lambda expression),也可稱為閉包(Closure),是 Java(SE)8 中一個重要的新特性。Lambda 表達式允許我們通過表達式來代替功能接口。Lambda 表達式就和方法一樣,它提供了一個正常的參數(shù)列表和一個使用這些參數(shù)的主體(body,可以是一個表

    2024年02月13日
    瀏覽(33)

覺得文章有用就打賞一下文章作者

支付寶掃一掃打賞

博客贊助

微信掃一掃打賞

請作者喝杯咖啡吧~博客贊助

支付寶掃一掃領(lǐng)取紅包,優(yōu)惠每天領(lǐng)

二維碼1

領(lǐng)取紅包

二維碼2

領(lǐng)紅包