Java8中你可能不知道的一些地方之Lambda

2020-12-03 樂字節教育

Lambda 表達式(也稱為閉包),它允許我們將函數當成參數傳遞給某個方法,或者把代碼本身當作數據處理。很多語言(Groovy、Scala等)從設計之初就支持 Lambda 表達式。但是 java 中使用的是匿名內部類代替。最後藉助強大的社區力量,找了一個折中的 Lambda 實現方案,可以實現簡潔而緊湊的語言結構。

一、匿名內部類到Lambda的演化

匿名內部類,即一個沒有名字的,存在於一個類或方法內部的類。當我們需要用某個類且只需要用一次,創建和使用合二為一時,我們可以選擇匿名內部類,省掉我們定義類的步驟。

匿名內部類會隱式的繼承一個類或實現一個接口,或者說匿名內部類是一個繼承了該類或者實現了該接口的子類匿名對象。下面看一個匿名內部類的例子:

測試類中調用方法

package com.lotbyte.main;

/*

定義和使用匿名內部類

*/

public class NoNameClass {

public static void main(String[] args) {

Model m = new Model(){

@Override

public void func() {

System.out.println("方法的實現");

}

};

m.func();

}

}

// 需要被實現的接口

interface Model{

void func();

}

二、Lambda快速使用

從某種意義上來說,Lambda 表達式可以看作是匿名內部類對象的簡寫形式。最簡單的 Lambda 表達式可以由用

逗號分隔的參數列表

->

符號和

語句塊

組成。

注意:此時匿名內部類只能實現接口,不能是繼承抽象類

例如將上面的例子做一個簡化,使用 Lambda 的形式如下:

public class NonameClassForLambda {

public static void main(String[] args) {

// Lambda方式簡寫,方法實現可以很簡單

Model1 md = ()-> System.out.println("hello");

md.func();

// 也可以是比較複雜的操作

md = () -> {

for (int i = 1; i <=5; i++) {

System.out.println(i);

}

};

md.func();

}

}

// 接口

interface Model1{

void func();

}

以上是一個簡單的 Lambda 的書寫形式,

()

中是形參列表,沒有則為空括號,

->

為語法格式,之後則為方法的實現(一條語句可以直接書寫,當有多條語句時,需要使用

{}

進行包裹)。從這可以看出在接口中必須只能存在一個抽象方法。

注意:Lambda中必須有個接口

三、Lambda的形式

使用 Lambda 時,實現方法可以有參數,也可以有返回值,如果沒指定參數類型,則由編譯器自行推斷得出。

3.1、 無參帶返回值

生成[1,10]之間的任意整數

interface Model2{

int func();

}

Model2 md2 = () -> {return (int)(Math.random()*10+1)};

說明:Lambda 的改寫需要有對應的抽象方法,當沒有參數時需要使用

()

佔位,當表達式只有一行代碼時,可以省略

return

{}

以上的 Lambda 等價於:

Model2 md2 = () -> (int)(Math.random()*10+1);

3.2 、帶參帶返回值

返回一個對數字描述的字符串

interface Model3{

String func(int a);

}

Model3 md3 = (int a) -> {

return "This is a number " + a;

};

說明:形參寫在

()

內即可,參數的類型可以省略,此時將由編譯器自行推斷得出,同時還可以省略

()

md3 = a -> "This is a number " + a;

省略了參數類型,小括號,同時連帶實現體的括號和 return 都省了。

3.3 、帶多個參數

根據輸入的運算符計算兩個數的運算,並返回結果

interface Model4{

String func(int a, int b, String oper);

}

Model4 md4 = (a, b, s) -> {

String res = "";

if("+".equals(s)){

res = ( a+b ) + "";

}else if("-".equals(s)){

res = ( a-b ) + "";

}else if("*".equals(s)){

res = ( a*b ) + "";

}else if("/".equals(s)){

res = ( a/b ) + ""; // 暫不考慮除0的情況

}else{

res = "操作有失誤";

}

return res;

};

System.out.println(md4.func(1,1,"+"));

以上例子為多個參數的 Lambda 表達式,其中省略掉了每一個參數的類型,編譯器自動推斷。多條語句時實現體的

{}

不能省。

最新技術學習資料(^_^) → lezijie007(程式設計師暗號:1024)

四、Lambda作為參數

在 jdk8 之前,接口可以作為方法參數傳入,執行時必須提供接口實現類的實例。從 java8 開始,Lambda 可以作為接口方法實現,當作參數傳入,無論從形式上還是實際上都省去了對象的創建。使代碼更加的緊湊簡單高效。

使用 Lambda 表達式需要有以下幾步:

1、定義接口,抽象方法的模板;

2、在某方法中需要接口作為參數;

3、調用方法時需要將抽象方法實現(此時我們使用 Lambda 表達式)並傳入即可。

4.1、定義接口

在接口中,必須有且僅有一個抽象方法,以確定 Lambda 模板

// 無參無返回值的方法

interface LambdaInterface1{

void printString();

}

// 帶參無返回值的方法

interface LambdaInterface2{

void printString(String str);

}

4.2、定義方法接收參數

在某方法中需要使用接口作為參數

// 無參

public static void testLambda(LambdaInterface1 lam1){

lam1.printString();

}

// 帶參

public static void testLambda2(String s,LambdaInterface2 lam2){

lam2.printString(s);

}

4.3、Lambda實現

使用方法時需要用 Lambda 將抽象方法實現

// 無參Lambda作為參數

testLambda(()->{

System.out.println("可以簡單,可以複雜");

});

// 帶參Lambda作為參數

testLambdaParam("hello",(a)->{

System.out.println(a);

});

通過以上三步,能夠完整地展示 Lambda 如何演變而來。此後在使用時,jdk 中已經提供很多場景了,即前兩部已經完成,我們更多的是實現第三步即可。

五、forEach展示Lambda

例如以 ArrayList 的遍歷為例子,分析 Lambda 的使用方式。

public static void main(String[] args) {

List<String> strs = new ArrayList<String>(){

{

add("aaa");

add("bbb");

add("ccc");

}

};

strs.forEach((str)-> System.out.println(str));

}

下面看看 forEach 的源碼,定義中使用了接口 Consumer 作為參數,並調用了其方法:

Consumer 中的抽象方法只有 accept 一個:

通過在 forEach 方法中調用 Consumer 的 accept 方法,並將每一個元素作為參數傳入,使得 accept 方法可以對每一個元素進行操作,當我們使用 Lambda 實現 accept 時就變成了我們自己對每一個元素的處理了。我們只負責處理即可。

六、Lambda中使用變量

在 Lambda 中可以定義自己的局部變量,也可以使用外層方法的局部變量,還可以使用屬性。這一點也不難理解,既然是一個方法的實現,只寫了一個代碼塊,那麼使用本身所屬方法的局部變量和類的屬性也並不過分。

public static void main(String[] args) {

List<String> strs = new ArrayList<String>(){

{

add("aaa");

add("bbb");

add("ccc");

}

};

int j = 1;

strs.forEach((str)->{

int i = 0;

System.out.println(str + " " + i + " " + j);

});

}

注意:此時外部局部變量將自動變為 final

七、Lambda作為方法返回值

例子:返回判斷字符串是否為空

public class Demo004_2 {

public static void main(String[] args) {

System.out.println(testLambda().isEmpty("string"));

}

// 判斷字符串是否為空

public static AssertEmpty testLambda(){

return (n)-> null==n||n.trim().isEmpty(n);

}

}

interface AssertEmpty{

boolean isEmpty(String str);

}

相關焦點

  • Java8 lambda表達式
    編寫第一個lambda表達式swing是一個平臺無關的gui庫,在該庫中,有很多常見的習慣,比如為了知道用戶點點擊了什麼,註冊一個事件監聽器,這個事件監聽器可以執行一些操作響應用戶的輸入。同匿名內部類做法另外一種不同就是,我們申明變量的方式,之前,我們需要顯示申明類型ActionEvent,在該例中,我們不需要提供類型,編譯也能通過,在這背後發生的是javac從上下文獲取event類型,此處是從addActionListener籤名中獲取,這意味著你不需要顯示申明其類型,我們之後會更加詳細討論這種設計,首先讓我們看看編寫lambda表達式幾種不同的方法。
  • Java8 lambda表達式語法
    文中如有錯誤和理解偏差的地方,希望大家幫忙指出,我會持續修改和優化。本文是該系列的第一篇,主要介紹Java8對屌絲碼農最有吸引力的一個特性—lambda表達式。java8的安裝工欲善其器必先利其器,首先安裝JDK8。過程省略,大家應該都可以自己搞定。
  • 大家都在說的「Lambda 表達式」到底是什麼?
    自從java8中引入了Lambda表達式之後,使用的人也越來越多了,這篇文章我們就來看看什麼是Lambda表達式。廢話少說,先看定義!2、簡單了解一下lambda的語法格式(參數) ->{語句; }上面就是lambda的語法格式,「->」是它的一個標誌,當你看到「->」你就知道這裡使用了Lambda表達式。3、再來看一下Lambda的特徵可選類型聲明:不需要聲明參數類型,編譯器可以統一識別參數值。
  • python入門基礎之lambda匿名函數詳解
    python入門基礎之lambda匿名函數詳解剛開始學習python的時候很多人可能對於lambda函數不了解,感覺和def很混亂,下面我來介紹一下lambda函數我從一下幾個方面來介紹lambda:lambda作為一個表達式,定義了一個匿名函數,上例的代碼x,y為入口參數,x+y為函數體。在這裡lambda簡化了函數定義的書寫形式。python允許用lambda關鍵字創造匿名函數。匿名是不需要以標準的方式來聲明,比如說使用 def 語句。(除非賦值給一個局部變量,這樣的對象也不會在任何的名字空間內創建名字,上面的例子中會創建名字。)
  • Python中的Lambda表達式
    Lambda表達式當我們需要做一些簡單的事情並且更希望快速完成工作而不是正式命名函數時,Lambda表達式是理想的選擇。Lambda表達式也稱為匿名函數。Python中的Lambda表達式是聲明小型匿名函數的一種簡短方式(沒有必要為Lambda函數提供名稱)。
  • Lambda表達式在Python事件中的運用
    本篇筆記內容:Lambda表達式詳解Lambda表達式在事件中的應用【1】Lambda表達式詳解lambda 表達式定義的是一個匿名函數,只適合簡單輸入參數,簡單計算返回結果,不適合功能複雜情況。lambda 定義的匿名函數也有輸入、也有輸出,只是沒有名字。語法格式如下:lambda 參數值列表:表達式其中,參數值列表即為輸入,表達式計算的結構即為輸出。看一個案例:求三個數的和。
  • Java中Lambda表達式的5種不同語法
    Arrays.sort(arr, (String m, String n) -> Integer.compare(m.length(), n.length()));System.out.println(Arrays.toString(arr));lambda
  • lambda匿名函數都自嘆不如
    其中,一行代碼編寫與lambda表達式是最具代表性的方法,下面分別來介紹一行代碼編寫和lambda表達式的代碼之美。一行代碼我們都知道,創建列表的方式有多種,比如直接定義、使用list()函數轉換、使用for循環迭代輸出等等。
  • Python中函數的定義、傳參和lambda函數是什麼?他們有什麼用?
    今天我們來學習函數的定義、傳參和lambda函數。開發工具:IDLE (Python 3.7 64-bit或者32-bit) (註:不需要3.7版本的也行,只需要Python3的版本都可以,在語法方面沒有什麼不同。)
  • Python面試題推薦:什麼是lambda函數?
    Python允許你定義一種單行的小函數。定義lambda函數的形式如下:labmda 參數:表達式lambda函數默認返回表達式的值。你也可以將其賦值給一個變量。lambda函數可以接受任意個參數,包括可選參數,但是表達式只有一個:>>> g = lambda x, y: x*y>>> g(3,4)12>>> g = lambda x, y=0,
  • 「數據清洗」lambda表達式配合使用的四種函數
    lambda表達式常用來聲明匿名函數,即沒有函數名字的臨時使用的小函數,常用在臨時需要一個類似於函數的功能但又不想定義函數的場合。它只可以包含一個表達式,不允許包含其他複雜的語句,但在表達式中可以調用其他函數,該表達式的計算結果相當於函數的返回結果。lambda表達式可以接受任意數量的參數,但函數只能包含一個表達式。
  • Python匿名函數:Lambda表達式
    我們以一張圖形進入主題:從圖中我們可以看出lambda表達式幾點特徵:簡潔性,符合了Python的一貫宗旨;起到了函數的作用,但未顯示函數名稱,這就是匿名函數;首先,看一個返回所有參數和的函數:# 返回所有參數和def pSum(a,b,c):return a + b + cpSum(10,40,50)函數中必須要用
  • Python學習第40課-Lambda表達式創建匿名函數
    Python中可以使用Lambda表達式來創建匿名函數。lambda表達式用來創建匿名函數,那麼我們也可以把lambda表達式叫做lambda函數。●Lambda函數的特點lambda函數只需要寫一行代碼,函數體比用def定義的函數體簡單。lambda函數有自己的命名空間,且不能訪問自己命名空間之外或全局命名空間裡的參數。
  • Python小白學習記錄-匿名函數lambda
    匿名函數就是不需要通過def定義及顯示地指定函數名的函數匿名函數的特性(1)匿名函數只能有一個表達式,不用寫return,返回值就是該表達式的結果。(4)有些函數在代碼中只用一次,而且函數體比較簡單,不需要賦值給變量,直接調用可以減少代碼量,看起來比較」優雅「。
  • 關於城市廢墟,你可能不知道的
    當時可能沒什麼感覺,現在回想起來記憶中的感覺其實是挺深刻的,我其實相信像我那個年紀的很多小孩,成長的環境可能也都是父母親在那種大型的工廠裡面,我記得我們當時濱湖機械廠周邊還有武漢重型工具機廠(音),無線電廠、電視機廠都在那一塊兒,我的小學同學都是這些單位裡成長起來的。
  • Python每天一分鐘:lambda表達式 (匿名函數)及用法詳解
    lambda表達式介紹python中有一種靈活,便捷的且具有函數功能的表達式:lambda表達式!,它可以在程序中被傳遞和調用。一個lambda表達式範例本例中使用了多種python的小技巧,包括python推導式,map函數,lambda表達式等。
  • 那個偷走愛因斯坦大腦的故事,背後您可能不知道的一些事
    這曾是一起當年轟動全球的事件,偷盜者曾被千夫所指,受盡責難,其過程不需要多做敘述了。今天我們這裡主要說的是背後的一些故事。也許你知道,也許有的你還真不知道。在這裡,我們先來看看一位上世紀九十年代著名的病理專家的回憶:這位一位病理學家是一位留美華人,在1990年,幸運地親眼目睹了愛因斯坦大腦的組織結構。
  • 三種基本用法、五種應用場景,理清C++11新特性:Lambda表達式
    lambda表達式是指能夠捕獲作用域中的變量的無名函數對象,狹義的理解,就是匿名函數。無論是在項目中,還是在開源網站,總是能夠看到lambda的身影。為了能夠輕鬆閱讀代碼,進而熟練地使用,本文首先將講解lambda表達式的基本語法、三種基本用法,然後介紹五種實際的應用場景,最有總結說明lambda表達式的作用。
  • CSharp 基礎知識系列- 6 Lambda表達式和Linq簡單介紹
    嗯,簡單來講就是匿名函數,我們不聲明方法名,只寫一個方法體,這個方法體就是lambda表達式1. lambda表達式1.1 如何寫一個lambda表達式首先,在寫lambda表達式之前,需要先了解兩個特殊的類型:Func和Action。這是兩個委託,這裡先不急著了解什麼是委託,可以把它們當做一種名稱規範就行,它們都可以表示一個方法。