Java8-Lambda表示式

sunankang發表於2020-12-29

Lambd

lambda表示式是java8的新特性,可以使用函式式介面替換掉原來的匿名內部類

lambda的本質就是引用一個已經具體實現的方法來完成對函式式介面抽象方法的具體實現

例如現在有一個介面,裡面只有一個求和方法

public interface Mylambda {
    int sum(int a,int b);
}

我們現在想要使用這個方法,有三種方式

  1. 建立一個類實現這個介面
  2. 匿名內部類
  3. 使用lambda函式式介面

第一種方法就不說了,來看使用匿名內部類

Mylambda myLambda=new Mylambda() {
    @Override
    public int sum(int a, int b) {
        return a+b;
    }
};

然後呼叫myLambda的sum方法可以做到求和的操作

再來看看lambda

Mylambda myLambda=(int a,int b)->{
    return a+b;
};

()->{} 什麼意思呢? 我們來看看lambda是如何使用的

() 裡面是傳入的引數

{} 裡面為方法體具體操作

需要注意的點

  1. lambda只能用於只有一個方法的介面
  2. 最好在介面上新增註解@FunctionalInterface來表明這是一個函式式介面
  3. 引數型別因為已經在介面中定義,那麼傳入引數時可以不用寫引數型別,要麼引數都寫引數型別,要不然都不寫引數型別
  4. 引數的數量,型別,順序必須和介面中一致

那麼lambda就這些嗎? 當然不是,還可以簡化以及拆分方法

簡化

如果方法體中就只有一條return語句,例如上面sum方法中,那麼在lambda表示式中可以省略大括號以及return

public static void main(String[] args) {
    Mylambda mylambda = (a,b) -> a + b;
}

如果引數只有一個,可以省略小括號

例如下面這個介面,我們並沒有做任何操作,只是將傳入引數原封不動返回,只是為了學習使用

@FunctionalInterface
public interface MyLambda2 {
    int print(int i);
}

使用

public static void main(String[] args) {
    MyLambda2 myLambda2= i -> i;
}

是不是看的有點蒙呢,不簡化就是

MyLambda2 myLambda2= (i) -> {
    return i;
};

因為引數只有一個,而且返回值也只有一條return語句,所以省略了傳入引數的小括號以及方法體的大括號和return關鍵字

這裡也有個需要注意的點 : 方法體的大括號和return語句要麼都省略,不能只省略一個

如果方法中僅僅想返回一個物件,不做任何其他操作,還可以簡化

//介面============
@FunctionalInterface
public interface MyLambda2 {
    User getUser();
}
//使用,未簡化前===========
public static void main(String[] args) {
    MyLambda2 myLambda=()->{
        return  new User();
    };
}
//再根據引數和方法體簡化=====
public static void main(String[] args) {
    MyLambda2 myLambda2=()->new User();
}
//使用,簡化後
public static void main(String[] args) {
    MyLambda2 myLambda=User::new;
}

上面兩個簡化估計都可以看懂,但是最後一個User::new 估計有點蒙,什麼意思呢?

在開頭就講過 lambda的本質就是引用一個已經具體實現的方法來完成對函式式介面抽象方法的具體實現

而lambda建立User物件說白了就是呼叫User的構造方法,而lambda呼叫物件的構造方法的語法就是 型別::new也就是上面寫的User::new

那麼如果想通過lambda呼叫物件的有參構造呢?

很遺憾,不能通過這種方式來呼叫物件的有參構造,如果想通過lambda呼叫,我們可以稍微簡化為下面這種

//介面========
@FunctionalInterface
public interface MyLambda2 {
    User getUser(String name,int age);
}
//測試=============
public static void main(String[] args) {
    MyLambda2 myLambda2=(name,age)->new User();
}

拆分

那麼如果一個方法我們經常使用該怎麼辦呢,難道每次都去複製原來的lambda表示式嗎?

可以將常用的方法單獨拆分出來,每次lambda表示式去呼叫這個方法即可

我們以上面的sum介面為例 :

//介面===================
@FunctionalInterface
public interface Mylambda {
    int sum(int a,int b);
}
//測試==================
public static void main(String[] args) {
    Mylambda mylambda = (a,b)-> doSum(a,b);
    int sum = mylambda.sum(2, 5);
}
//抽取出的方法( 注意是靜態呼叫靜態,如果是普通方法需要建立物件 )===============
public static int doSum(int a,int b){
    return a+b;
}

我們將求和的操作單獨拆分為一個方法,每次使用時只需要呼叫這個方法即可

() -> xxx();

也就是說lambda不僅可以直接寫方法具體細節,也可以呼叫其他方法,需要注意的時呼叫的方法返回值必須和介面定義返回值一致
當然,呼叫拆分的方法也可以簡化,使用方法如下

靜態類 類名::方法

非靜態 物件::方法

對於靜態的拆分方法

//介面=======
@FunctionalInterface
public interface Mylambda {
    int sum(int a,int b);
}
//測試類名為Test=========
public static void main(String[] args) {
    Mylambda myLambda=Test::doSum;
}
//拆分的方法========
public static int doSum(int a,int b){
    return a+b;
}

對於非靜態的拆分方法


//介面=======
@FunctionalInterface
public interface Mylambda {
    int sum(int a,int b);
}
//測試類名為Test=========
public static void main(String[] args) {
    Test test = new Test();
    Mylambda myLambda=test::doSum;
}
//拆分的方法========
public static int doSum(int a,int b){
    return a+b;
}

兩者區別僅僅是在於物件::方法類::方法,因為非靜態類需要建立出物件才可以呼叫方法

當使用簡化後的呼叫方法那麼會自動匹配引數型別,數量和順序,所以更加要嚴謹仔細,確保引數一一對應

再說一遍吧,lambda的本質就是引用一個已經具體實現的方法來完成對函式式介面抽象方法的具體實現,那麼現在再來看這句話是不是清楚很多呢

本文僅個人理解,如果有不對的地方歡迎評論指出或私信,謝謝٩(๑>◡<๑)۶

相關文章