Lambda 表達式入門,這篇夠了!

2021-03-02 網際網路架構師
Lambda簡介

Lambda 表達式是 JDK8 的一個新特性,可以取代大部分的匿名內部類,寫出更優雅的 Java 代碼,尤其在集合的遍歷和其他集合操作中,可以極大地優化代碼結構。

JDK 也提供了大量的內置函數式接口供我們使用,使得 Lambda 表達式的運用更加方便、高效。

對接口的要求

雖然使用 Lambda 表達式可以對某些接口進行簡單的實現,但並不是所有的接口都可以使用 Lambda 表達式來實現。Lambda 規定接口中只能有一個需要被實現的方法,不是規定接口中只能有一個方法

jdk 8 中有另一個新特性:default, 被 default 修飾的方法會有默認實現,不是必須被實現的方法,所以不影響 Lambda 表達式的使用。

@FunctionalInterface

修飾函數式接口的,要求接口中的抽象方法只有一個。這個註解往往會和 lambda 表達式一起出現。

Lambda 基礎語法

我們這裡給出六個接口,後文的全部操作都利用這六個接口來進行闡述。

/**多參數無返回*/  
@FunctionalInterface  
public interface NoReturnMultiParam {  
    void method(int a, int b);  
}  
  
/**無參無返回值*/  
@FunctionalInterface  
public interface NoReturnNoParam {  
    void method();  
}  
  
/**一個參數無返回*/  
@FunctionalInterface  
public interface NoReturnOneParam {  
    void method(int a);  
}  
  
/**多個參數有返回值*/  
@FunctionalInterface  
public interface ReturnMultiParam {  
    int method(int a, int b);  
}  
  
/*** 無參有返回*/  
@FunctionalInterface  
public interface ReturnNoParam {  
    int method();  
}  
  
/**一個參數有返回值*/  
@FunctionalInterface  
public interface ReturnOneParam {  
    int method(int a);  
}  
 

語法形式為 () -> {},其中 () 用來描述參數列表,{} 用來描述方法體,-> 為 lambda運算符 ,讀作(goes to)。

import lambda.interfaces.*;  
  
public class Test1 {  
    public static void main(String[] args) {  
  
        //無參無返回  
        NoReturnNoParam noReturnNoParam = () -> {  
            System.out.println("NoReturnNoParam");  
        };  
        noReturnNoParam.method();  
  
        //一個參數無返回  
        NoReturnOneParam noReturnOneParam = (int a) -> {  
            System.out.println("NoReturnOneParam param:" + a);  
        };  
        noReturnOneParam.method(6);  
  
        //多個參數無返回  
        NoReturnMultiParam noReturnMultiParam = (int a, int b) -> {  
            System.out.println("NoReturnMultiParam param:" + "{" + a +"," + + b +"}");  
        };  
        noReturnMultiParam.method(6, 8);  
  
        //無參有返回值  
        ReturnNoParam returnNoParam = () -> {  
            System.out.print("ReturnNoParam");  
            return 1;  
        };  
  
        int res = returnNoParam.method();  
        System.out.println("return:" + res);  
  
        //一個參數有返回值  
        ReturnOneParam returnOneParam = (int a) -> {  
            System.out.println("ReturnOneParam param:" + a);  
            return 1;  
        };  
  
        int res2 = returnOneParam.method(6);  
        System.out.println("return:" + res2);  
  
        //多個參數有返回值  
        ReturnMultiParam returnMultiParam = (int a, int b) -> {  
            System.out.println("ReturnMultiParam param:" + "{" + a + "," + b +"}");  
            return 1;  
        };  
  
        int res3 = returnMultiParam.method(6, 8);  
        System.out.println("return:" + res3);  
    }  
}  

Lambda 語法簡化

我們可以通過觀察以下代碼來完成代碼的進一步簡化,寫出更加優雅的代碼。

import lambda.interfaces.*;  
  
public class Test2 {  
    public static void main(String[] args) {  
  
        //1.簡化參數類型,可以不寫參數類型,但是必須所有參數都不寫  
        NoReturnMultiParam lamdba1 = (a, b) -> {  
            System.out.println("簡化參數類型");  
        };  
        lamdba1.method(1, 2);  
  
        //2.簡化參數小括號,如果只有一個參數則可以省略參數小括號  
        NoReturnOneParam lambda2 = a -> {  
            System.out.println("簡化參數小括號");  
        };  
        lambda2.method(1);  
  
        //3.簡化方法體大括號,如果方法條只有一條語句,則可以勝率方法體大括號  
        NoReturnNoParam lambda3 = () -> System.out.println("簡化方法體大括號");  
        lambda3.method();  
  
        //4.如果方法體只有一條語句,並且是 return 語句,則可以省略方法體大括號  
        ReturnOneParam lambda4 = a -> a+3;  
        System.out.println(lambda4.method(5));  
  
        ReturnMultiParam lambda5 = (a, b) -> a+b;  
        System.out.println(lambda5.method(1, 1));  
    }  
}  

Lambda 表達式常用示例lambda 表達式引用方法

有時候我們不是必須要自己重寫某個匿名內部類的方法,我們可以可以利用 lambda表達式的接口快速指向一個已經被實現的方法。關注公眾號網際網路架構師回復獲取我寫的java系列教程。

語法

方法歸屬者::方法名 靜態方法的歸屬者為類名,普通方法歸屬者為對象

public class Exe1 {  
    public static void main(String[] args) {  
        ReturnOneParam lambda1 = a -> doubleNum(a);  
        System.out.println(lambda1.method(3));  
  
        //lambda2 引用了已經實現的 doubleNum 方法  
        ReturnOneParam lambda2 = Exe1::doubleNum;  
        System.out.println(lambda2.method(3));  
  
        Exe1 exe = new Exe1();  
  
        //lambda4 引用了已經實現的 addTwo 方法  
        ReturnOneParam lambda4 = exe::addTwo;  
        System.out.println(lambda4.method(2));  
    }  
  
    /**  
     * 要求  
     * 1.參數數量和類型要與接口中定義的一致  
     * 2.返回值類型要與接口中定義的一致  
     */  
    public static int doubleNum(int a) {  
        return a * 2;  
    }  
  
    public int addTwo(int a) {  
        return a + 2;  
    }  
}  

構造方法的引用

一般我們需要聲明接口,該接口作為對象的生成器,通過 類名::new 的方式來實例化對象,然後調用方法返回對象。

interface ItemCreatorBlankConstruct {  
    Item getItem();  
}  
interface ItemCreatorParamContruct {  
    Item getItem(int id, String name, double price);  
}  
  
public class Exe2 {  
    public static void main(String[] args) {  
        ItemCreatorBlankConstruct creator = () -> new Item();  
        Item item = creator.getItem();  
  
        ItemCreatorBlankConstruct creator2 = Item::new;  
        Item item2 = creator2.getItem();  
  
        ItemCreatorParamContruct creator3 = Item::new;  
        Item item3 = creator3.getItem(112, "滑鼠", 135.99);  
    }  
}  

lambda 表達式創建線程

我們以往都是通過創建 Thread 對象,然後通過匿名內部類重寫 run() 方法,一提到匿名內部類我們就應該想到可以使用 lambda 表達式來簡化線程的創建過程。

Thread t = new Thread(() -> {  
  for (int i = 0; i < 10; i++) {  
    System.out.println(2 + ":" + i);  
  }  
});  
t.start();  
 

遍歷集合

我們可以調用集合的public void forEach(Consumer<? super E> action) 方法,通過 lambda 表達式的方式遍歷集合中的元素。以下是 Consumer 接口的方法以及遍歷集合的操作。Consumer 接口是 jdk 為我們提供的一個函數式接口。

@FunctionalInterface  
public interface Consumer<T> {  
    void accept(T t);  
    //....  
}  

ArrayList<Integer> list = new ArrayList<>();  

Collections.addAll(list, 1,2,3,4,5);  

//lambda表達式 方法引用  
list.forEach(System.out::println);  

list.forEach(element -> {  
  if (element % 2 == 0) {  
    System.out.println(element);  
  }  
});  

刪除集合中的某個元素

我們通過public boolean removeIf(Predicate<? super E> filter)方法來刪除集合中的某個元素,Predicate 也是 jdk 為我們提供的一個函數式接口,可以簡化程序的編寫。

ArrayList<Item> items = new ArrayList<>();  
items.add(new Item(11, "小牙刷", 12.05 ));  
items.add(new Item(5, "日本馬桶蓋", 999.05 ));  
items.add(new Item(7, "格力空調", 888.88 ));  
items.add(new Item(17, "肥皂", 2.00 ));  
items.add(new Item(9, "冰箱", 4200.00 ));  

items.removeIf(ele -> ele.getId() == 7);  

//通過 foreach 遍歷,查看是否已經刪除  
items.forEach(System.out::println);  

集合內元素的排序

在以前我們若要為集合內的元素排序,就必須調用 sort 方法,傳入比較器匿名內部類重寫 compare 方法,我們現在可以使用 lambda 表達式來簡化代碼。

ArrayList<Item> list = new ArrayList<>();  
list.add(new Item(13, "背心", 7.80));  
list.add(new Item(11, "半袖", 37.80));  
list.add(new Item(14, "風衣", 139.80));  
list.add(new Item(12, "秋褲", 55.33));  

/*  
list.sort(new Comparator<Item>() {  
    @Override  
    public int compare(Item o1, Item o2) {  
        return o1.getId()  - o2.getId();  
    }  
});  
*/  

list.sort((o1, o2) -> o1.getId() - o2.getId());  

System.out.println(list);  

Lambda 表達式中的閉包問題

這個問題我們在匿名內部類中也會存在,如果我們把注釋放開會報錯,告訴我 num 值是 final 不能被改變。這裡我們雖然沒有標識 num 類型為 final,但是在編譯期間虛擬機會幫我們加上 final 修飾關鍵字。

import java.util.function.Consumer;  
public class Main {  
    public static void main(String[] args) {  
  
        int num = 10;  
  
        Consumer<String> consumer = ele -> {  
            System.out.println(num);  
        };  
  
        //num = num + 2;  
        consumer.accept("hello");  
    }  
}

相關焦點

  • Lambda 表達式入門,看這篇就夠了!
    這個註解往往會和 lambda 表達式一起出現。Lambda 基礎語法我們這裡給出六個接口,後文的全部操作都利用這六個接口來進行闡述。}Lambda 表達式常用示例lambda 表達式引用方法有時候我們不是必須要自己重寫某個匿名內部類的方法,我們可以可以利用 lambda表達式的接口快速指向一個已經被實現的方法。
  • Python中的Lambda表達式
    Lambda表達式當我們需要做一些簡單的事情並且更希望快速完成工作而不是正式命名函數時,Lambda表達式是理想的選擇。Lambda表達式也稱為匿名函數。Python中的Lambda表達式是聲明小型匿名函數的一種簡短方式(沒有必要為Lambda函數提供名稱)。
  • Java中Lambda表達式的5種不同語法
    表達式的標準語法包括以下內容:1.主體,由單個表達式或語句塊組成。這使代碼更整潔,更像真正的lambda表達式。3. Lambda表達式中的多行代碼如果代碼不能一行編寫,則可以將其括在{}中。現在,該代碼應明確包含return語句。
  • Lambda 表達式,簡潔優雅就是生產力!
    這是我認為理解Lambda的一個關鍵所在,簡而言之就是,Lambda表達式本身就是一個接口的實現。直接這樣說可能還是有點讓人困擾,我們繼續看看例子。我們給上面的aBlockOfCode加上一個類型:這種只有一個接口函數需要被實現的接口類型,我們叫它」函數式接口「。
  • 編譯器說 Lambda 表達式中的變量必須是 final 的,我偏不信 | 原力計劃
    ,它會警告我們說:「variable used in lambda expression should be final or effectively final」。這個問題發生的原因是因為 Java 規範中是這樣規定的:Any local variable, formal parameter, or exception parameter used but not declared in a lambda
  • Python零基礎入門教程,如何使用lambda、filter和map函數?
    大綱函數類型定義及特性lambda函數定義及使用filter函數定義及使用map函數定義及使用引入函數類型概念函數類型定義:python中任意一個函數都有數據類型,這種數據類型是function(函數類型)
  • lambda qt 參數 槽函數 - CSDN
    匿名函數也可以被叫做Lambda表達式,自C++11中引入該特性。本文主要介紹Qt裡使用到的匿名函數。1. connect中使用connect中可以使用匿名函數代替槽函數進行一些簡單操作。
  • 不來看看 Lambda 爽一下?
    一、java重要的函數式接口1、什麼是函數式接口「函數接口是只有一個抽象方法的接口,用作 Lambda 表達式的類型。「注意:Student::getName」例子中這種編寫lambda表達式的方式稱為「方法引用。「格式為」ClassNmae::methodName」。是不是很神奇,java8就是這麼迷人。
  • AE表達式新手入門必學篇
    以下是我掉坑的血淚史之前開始學習AE,後來想嘗試用ae表達式做個動畫,花了一天時間,終於熬出這麼一個小動畫:其中用到的知識點包括操控點和表達式。,所以array_a = array[0];這樣就將array內部元素a的值賦給了array_a對象~好了,還有更多其他術語什麼的對新手來說應該還不需要,我們只了解上面幾個應該就夠了。
  • Java之使用Lambda表達式,定義一個無參數無返回值的方法
    各位小夥伴們大家好,在之前的文章中,小編簡單介紹了Lambda表達式Java之Runnable表達式的簡單介紹,這次小編要介紹的是,使用Lambda表達式,定義一個無參數無返回值的方法參數傳遞Phone接口,方法內部調用Phone接口中的方法ringUppublic static void invokePhone(Phone call) {call.ringUp();}}這是用
  • 床長人工智慧教程——表達式列表
    元組的長度是列表中表達式的數量。表達式從左到右求值。星號*表示可重複拆包。它的操作數必須是可迭代的。可迭代的對象被擴展為一系列項目,這些項目包含在拆包現場的新元組,列表或集合中。版本3.5中的新功能:表達式列表中的可迭代拆包,最初由提議PEP 448。
  • 如何快速學會Python爬蟲(入門篇)
    一、爬蟲入門Python爬蟲入門一之綜述2. Python爬蟲入門二之爬蟲基礎了解3. Python爬蟲入門三之Urllib庫的基本使用4. Python爬蟲入門四之Urllib庫的高級用法5. Python爬蟲入門五之URLError異常處理6.
  • 使用NodeJS Lambda函數查詢RDS MySQL資料庫
    最近,我第一次嘗試了AWS lambda。我的任務是查詢RDS MySQL資料庫。在這篇文章中,我將分享我的經驗。我得到的錯誤如下:我發現AWS本身不支持我們使用的MySQL模塊,因此我們需要提供捆綁的ZIP文件作為lambda函數。
  • 如何入門Python之Python基礎教程詳解
    隨著人工智慧的發展,Python近兩年也是大火,越來越多的人加入到Python學習大軍,對於毫無基礎的人該如何入門Python呢?這裡整理了一些個人經驗和Python入門教程供大家參考。如果你是零基礎入門 Python 的話,建議初學者至少達到兩個目標: 會用,理解。
  • 雞尾酒入門?讀完這篇就夠了!
    很多朋友希望能讀到一篇詳細全面的雞尾酒入門科普,今天它來了!讀完這篇,輕鬆開啟你的雞尾酒之旅~雞尾酒相較其他酒類,最大的優點在於它的靈活,多變。如果你是一個勇於嘗試新鮮事物,總是不滿足於一種口味的酒客,那雞尾酒的世界一定可以給你你酒精和味蕾的雙重滿足。
  • java正則表達式入坑指南
    在日常開發工作中,無論你使用的語言是java、python、shell、golang還是C#, 正則表達式是程式語言中幾乎繞不開的話題。有了它,可以幫你快速定位到符合條件的文本內容。今天小編帶大家一起來學習下正則表達式,相信通過這篇文章的介紹,能為以後的工作提供一個更清晰的思路。
  • 原創通俗易懂的Python的正則表達式,建議收藏
    正則表達式正則表達式是一個特殊的字符序列,由普通字符和元字符組成。元字符能幫助你方便的檢查一個字符串是否與某種模式匹配。正則表達式應用的場景也非常多。常見的比如:搜尋引擎的搜索、爬蟲結果的匹配、文本數據的提取等等都會用到,所以掌握甚至精通正則表達式是一個硬性技能,非常必要。
  • Java之Runnable表達式的簡單介紹
    各位小夥伴們大家好,這次小編要介紹的是Runnable表達式當我們要啟動一個線程去完成任務的時候,通常的做法會通過java.lang.Runnable接口來定義任務內容,並使用java.lang.Thread類來啟動線程,代碼如下:/*創建Runnable接口的實現類,重寫